-
Notifications
You must be signed in to change notification settings - Fork 30
Conversation
src/Data/StrMap.purs
Outdated
instance foldableWithIndex :: FoldableWithIndex String StrMap where | ||
foldlWithIndex f = fold (flip f) | ||
foldrWithIndex f z m = foldr (uncurry f) z (toArrayWithKey Tuple m) | ||
foldMapWithIndex = foldMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this one work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foldlWithIndex
: nearly equivalent tofold
. Theflip
convertsk -> acc -> v -> acc
tok -> v -> acc -> acc
.foldrWithIndex
: first unpack into an array ofTuple k v
, then use the standardfoldr
for arrays. Theuncurry
convertsk -> v -> acc -> acc
toTuple k v -> acc -> acc
suitable forfoldr
.foldMapWithIndex
: same asfoldMap
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant foldMap
specifically. I wasn't seeing how the types lined up. Could you please add a test?
src/Data/StrMap.purs
Outdated
instance traversableStrMap :: Traversable StrMap where | ||
traverse f ms = fold (\acc k v -> insert k <$> f v <*> acc) (pure empty) ms | ||
sequence = traverse id | ||
|
||
instance traversableWithIndexStrMap :: TraversableWithIndex String StrMap where | ||
traverseWithIndex f ms = fold (\acc k v -> insert k <$> f k v <*> acc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be defined in terms of sequence
and mapWithKey
? It doesn't have to be, just a thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently yes! :P
Um, so I tried adding a test that relates I think > runWriter (traverse_ tell ["1", "2", "3"])
(Tuple unit "123")
> runWriter (traverse_ tell (StrMap.fromFoldable [Tuple "a" "1", Tuple "b" "2", Tuple "c" "3"]))
(Tuple unit "321")
> fold (StrMap.fromFoldable [Tuple "a" "1", Tuple "b" "2", Tuple "c" "3"])
"123" This seems to fix it: - traverse f ms = fold (\acc k v -> insert k <$> f v <*> acc) (pure empty) ms
+ traverse f ms = fold (\acc k v -> flip (insert k) <$> acc <*> f v) (pure empty) ms I'm also a bit wary of |
That seems fine to me. Anyone else have comments here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since JavaScript doesn't define what order a for-in loop goes over the elements of an object, I'd prefer to also leave the order that StrMap instances iterate over their properties undefined. That is, I wouldn't describe the current Traversable
instance as "broken"; if the order is important, people should be using Array (Tuple String a)
anyway. So I'd suggest we not treat this as a breaking change.
Apart from that minor nitpick, this looks good to me 👍
src/Data/StrMap.purs
Outdated
@@ -112,10 +118,19 @@ instance foldableStrMap :: Foldable StrMap where | |||
foldr f z m = foldr f z (values m) | |||
foldMap f = foldMap (const f) | |||
|
|||
instance foldableWithIndex :: FoldableWithIndex String StrMap where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foldableWithIndexStrMap
?
I don't know if it's broken, but a |
At the moment I think it's whatever order the JS engine decides to use in a for-in loop, which is usually insertion order, not by key - but the order used in a for-in loop is not actually defined in the language spec AFAIK. For example: > entries = [Tuple "a" 1, Tuple "c" 3, Tuple "b" 2]
> m = SM.fromFoldable entries
> traverse_ logShow m
1
3
2 |
Seems like we could fix that easily enough by iterating over the sorted keys, right? |
Perhaps, but it's potentially quite a large performance cost. I don't see that there's a problem with the current |
If you want fast lookup, insert, & delete, and a traversal with a guaranteed order, you should be using |
Maybe we should deprecate StrMap, and move it to a JavaScript specific module, with the caveat that it matches JS iteration semantics. |
Obviously |
I'm not sure I'd agree JS objects necessarily have an ordering, in that a for-in loop has to iterate over them in some order, even if that order is unspecified and therefore unpredictable. It's maybe not ideal, but given that this is how they work, I think it would be strange for For the same reason, I'm not sure we should go as far as deprecating |
I mean deprecating it as a part of purescript-maps. It's clearly useful, but it isn't a general purpose data structure. It only exists as a hack for JS interop. if you wrote FFI bindings for a different backend, would you expect to keep all the same JS semantics? |
Also, it's frustrating that the API for it and Map are not kept in sync. People use it for very different use cases. |
Yes, that's a good point. If we were going to do this we should take the opportunity to rename it too, perhaps JSMap or something. |
Anyway we should probably move this to a separate issue at this point. |
Oops, should be fixed now. |
Great, thanks. So should we merge this, make a minor release, and open a new issue to decide what to do about |
Maybe it's better to not think of StrMap as an ordinary unordered map at all, since insertion is not commutative. Rather it behaves more like an array in that regard. (Though technically the standards don't prescribe any ordering.) |
Add
FunctorWithIndex
,FoldableWithIndex
, andTraversableWithIndex
instances forStrMap
.