Skip to content
This repository was archived by the owner on Oct 4, 2020. It is now read-only.

Commit 02e2e86

Browse files
authored
Merge pull request #116 from Rufflewind/master
Add *WithIndex instances for StrMap
2 parents b1f2475 + 9de5651 commit 02e2e86

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

src/Data/StrMap.purs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ import Control.Monad.ST as ST
5050
import Data.Array as A
5151
import Data.Eq (class Eq1)
5252
import Data.Foldable (class Foldable, foldl, foldr, for_)
53+
import Data.FoldableWithIndex (class FoldableWithIndex)
5354
import Data.Function.Uncurried (Fn2, runFn2, Fn4, runFn4)
55+
import Data.FunctorWithIndex (class FunctorWithIndex)
5456
import Data.Maybe (Maybe(..), maybe, fromMaybe)
5557
import Data.Monoid (class Monoid, mempty)
5658
import Data.StrMap.ST as SM
5759
import Data.Traversable (class Traversable, traverse)
58-
import Data.Tuple (Tuple(..), fst)
60+
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
61+
import Data.Tuple (Tuple(..), fst, uncurry)
5962
import Data.Unfoldable (class Unfoldable)
6063

6164
-- | `StrMap a` represents a map from `String`s to values of type `a`.
@@ -91,6 +94,9 @@ foreign import _fmapStrMap :: forall a b. Fn2 (StrMap a) (a -> b) (StrMap b)
9194
instance functorStrMap :: Functor StrMap where
9295
map f m = runFn2 _fmapStrMap m f
9396

97+
instance functorWithIndexStrMap :: FunctorWithIndex String StrMap where
98+
mapWithIndex = mapWithKey
99+
94100
foreign import _foldM :: forall a m z. (m -> (z -> m) -> m) -> (z -> String -> a -> m) -> m -> StrMap a -> m
95101

96102
-- | Fold the keys and values of a map
@@ -112,10 +118,19 @@ instance foldableStrMap :: Foldable StrMap where
112118
foldr f z m = foldr f z (values m)
113119
foldMap f = foldMap (const f)
114120

121+
instance foldableWithIndexStrMap :: FoldableWithIndex String StrMap where
122+
foldlWithIndex f = fold (flip f)
123+
foldrWithIndex f z m = foldr (uncurry f) z (toArrayWithKey Tuple m)
124+
foldMapWithIndex = foldMap
125+
115126
instance traversableStrMap :: Traversable StrMap where
116-
traverse f ms = fold (\acc k v -> insert k <$> f v <*> acc) (pure empty) ms
127+
traverse = traverseWithIndex <<< const
117128
sequence = traverse id
118129

130+
instance traversableWithIndexStrMap :: TraversableWithIndex String StrMap where
131+
traverseWithIndex f ms =
132+
fold (\acc k v -> flip (insert k) <$> acc <*> f k v) (pure empty) ms
133+
119134
-- Unfortunately the above are not short-circuitable (consider using purescript-machines)
120135
-- so we need special cases:
121136

test/Test/Data/StrMap.purs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ import Control.Monad.Eff (Eff)
66
import Control.Monad.Eff.Console (log, CONSOLE)
77
import Control.Monad.Eff.Exception (EXCEPTION)
88
import Control.Monad.Eff.Random (RANDOM)
9+
import Control.Monad.Writer (runWriter, tell)
910
import Data.Array as A
10-
import Data.Foldable (foldl)
11+
import Data.Foldable (foldl, foldr)
12+
import Data.FoldableWithIndex (foldlWithIndex, foldrWithIndex, foldMapWithIndex)
1113
import Data.Function (on)
1214
import Data.List as L
1315
import Data.List.NonEmpty as NEL
1416
import Data.Maybe (Maybe(..))
1517
import Data.NonEmpty ((:|))
1618
import Data.StrMap as M
1719
import Data.StrMap.Gen (genStrMap)
18-
import Data.Traversable (sequence)
19-
import Data.Tuple (Tuple(..), fst, uncurry)
20+
import Data.Traversable (sequence, traverse)
21+
import Data.TraversableWithIndex (traverseWithIndex)
22+
import Data.Tuple (Tuple(..), fst, snd, uncurry)
2023
import Partial.Unsafe (unsafePartial)
2124
import Test.QuickCheck ((<?>), quickCheck, quickCheck', (===))
2225
import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary)
@@ -198,6 +201,34 @@ strMapTests = do
198201
resultViaLists = m # M.toUnfoldable # map (\(Tuple k v) → Tuple k (f k v)) # (M.fromFoldable :: forall a. L.List (Tuple String a) -> M.StrMap a)
199202
in resultViaMapWithKey === resultViaLists
200203

204+
log "foldl = foldlWithIndex <<< const"
205+
quickCheck \(TestStrMap m :: TestStrMap String) ->
206+
let f z v = z <> "," <> v
207+
in foldl f "" m === foldlWithIndex (const f) "" m
208+
209+
log "foldr = foldrWithIndex <<< const"
210+
quickCheck \(TestStrMap m :: TestStrMap String) ->
211+
let f v z = v <> "," <> z
212+
in foldr f "" m === foldrWithIndex (const f) "" m
213+
214+
log "foldlWithIndex = foldrWithIndex with flipped operation"
215+
quickCheck \(TestStrMap m :: TestStrMap String) ->
216+
let f k z v = z <> "," <> k <> ":" <> v
217+
g k v z = k <> ":" <> v <> "," <> z
218+
in foldlWithIndex f "" m <> "," === "," <> foldrWithIndex g "" m
219+
220+
log "foldMapWithIndex f ~ traverseWithIndex (\\k v -> tell (f k v))"
221+
quickCheck \(TestStrMap m :: TestStrMap Int) ->
222+
let f k v = "(" <> "k" <> "," <> show v <> ")"
223+
resultA = foldMapWithIndex f m
224+
resultB = snd (runWriter (traverseWithIndex (\k v -> tell (f k v)) m))
225+
in resultA === resultB
226+
227+
log "traverse = traverseWithIndex <<< const (for m = Writer)"
228+
quickCheck \(TestStrMap m :: TestStrMap String) ->
229+
runWriter (traverse tell m) ===
230+
runWriter (traverseWithIndex (const tell) m)
231+
201232
log "sequence works (for m = Array)"
202233
quickCheck \(TestStrMap mOfSmallArrays :: TestStrMap (SmallArray Int)) ->
203234
let m = (\(SmallArray a) -> a) <$> mOfSmallArrays

0 commit comments

Comments
 (0)