I would like Sanctuary to provide Fantasy Land -compatible Map and Set types with value-based equality semantics. Ideally these values would be immutable, though this is not critical since Sanctuary would provide pure functions for merging and otherwise manipulating these values.
I would love to leverage the good work done by the Immutable.js team; I imagine implementing persistent data structures takes considerable effort!
The API provided by Immutable.js is of little importance since Sanctuary would expose functions for interacting with these values. The equality semantics of these types, though, are crucial.
This is unacceptable for my use case:
> Map([[[1, 2, 3], 'foo'], [[1, 2, 3], 'bar']])
Map { [1,2,3]: "foo", [1,2,3]: "bar" }
[1, 2, 3]
is the same value as [1, 2, 3]
. It should not be possible to have two map entries with the same key.
The handling of -0
is also problematic:
> Immutable.is(Map([[0, 0]]), Map([[-0, -0]]))
true
I realize it's possible to define the equality semantics of one's own types by defining equals
methods, but I wish to redefine the equality semantics of native types such as Array and Number. Is this possible? The relevant file appears to be is.js, but I see no hooks for customization.
It's possible that Sanctuary's Map type could wrap the Immutable.js Map type. This would provide:
- a way to handle
-0
; - an opportunity to perform value-based equality checks before performing an
assoc
operation which would normally result in a duplicate key; and - a place to define the various
fantasy-land/
methods.
Perhaps:
Map k v = { negativeZero :: Maybe v
, value :: ImmutableMap k v
, fantasy-land/equals :: Map k v ~> Map k v -> Boolean
, fantasy-land/map :: Map k v ~> (k -> a) -> Map a v
, fantasy-land/bimap :: Map k v ~> (k -> a, v -> b) -> Map a b
, ...
}
I'd like to be sure there's no other way to attain the desired equality semantics before creating wrappers such as the above. facebook/immutable-js#519 isn't promising.
Map
. I always tend to accept the limitations of JS. Moreover I doubt that objects used as keys inMap
s really benefit from persistent data structures, since they ought to be rather small, like value objects. Immutable.js seems to be more suitable for huge data structures like a redux store. – LatriaArray
andNumber
? Modifying such a crucial property of builtins could be devastating. – FreeheartedMap
type. Anyway, I'm curious how you solve this problem, since I experience a similar one with implementing monoidalNumber
s,Array
s etc. for a more genericfold
. – Latriaassoc
iating[1, 2, 3]
–'baz'
with an existing map would be very slow because we'd first need to see whether any of the keys is equal to[1, 2, 3]
? That's a problem, certainly. What do you have in mind for the newtype-like wrappers? Could they solve this problem? – Adhesivenewtype
in Haskell? E.g you could use aList
(with sensible equality) instead of an array, and aMyNumber
that distinguishes zeroes instead of a plain number. – FreeheartedImmutable.Map
or the nativeMap
. Users wouldn't need to know that the newtype makes use of some other Map type internally, nor would other users of that other Map type be affected in any way. – AdhesiveArray.prototype.equals
andNumber.prototype.equals
would solve the problem. – FreeheartedArray
andNumber
which defines your custom.equals
method, and then to instantiate the wrapper implicitly for all arrays and numbers that are passed into your wrappedMap
. – FreeheartedDict
which is capable of associating values to compound data keys, here and 2) a generic object equality function, here – Celiotomy