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

Commit 7bdd5c1

Browse files
authored
Merge pull request #96 from joshuahhh/master
Faster & simpler traverse for StrMap
2 parents c1a826b + 91cee50 commit 7bdd5c1

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

src/Data/StrMap.purs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Data.StrMap
1313
, insert
1414
, lookup
1515
, toUnfoldable
16+
, toAscUnfoldable
1617
, fromFoldable
1718
, fromFoldableWith
1819
, delete
@@ -50,7 +51,7 @@ import Data.Maybe (Maybe(..), maybe, fromMaybe)
5051
import Data.Monoid (class Monoid, mempty)
5152
import Data.StrMap.ST as SM
5253
import Data.Traversable (class Traversable, traverse)
53-
import Data.Tuple (Tuple(..), uncurry)
54+
import Data.Tuple (Tuple(..), fst)
5455
import Data.Unfoldable (class Unfoldable)
5556

5657
-- | `StrMap a` represents a map from `String`s to values of type `a`.
@@ -108,7 +109,7 @@ instance foldableStrMap :: Foldable StrMap where
108109
foldMap f = foldMap (const f)
109110

110111
instance traversableStrMap :: Traversable StrMap where
111-
traverse f ms = foldr (\x acc -> union <$> x <*> acc) (pure empty) ((map (uncurry singleton)) <$> (traverse f <$> toArray ms))
112+
traverse f ms = fold (\acc k v -> insert k <$> f v <*> acc) (pure empty) ms
112113
sequence = traverse id
113114

114115
-- Unfortunately the above are not short-circuitable (consider using purescript-machines)
@@ -132,6 +133,13 @@ instance eqStrMap :: Eq a => Eq (StrMap a) where
132133
instance eq1StrMap :: Eq1 StrMap where
133134
eq1 = eq
134135

136+
-- Internal use
137+
toAscArray :: forall v. StrMap v -> Array (Tuple String v)
138+
toAscArray = toAscUnfoldable
139+
140+
instance ordStrMap :: Ord a => Ord (StrMap a) where
141+
compare m1 m2 = compare (toAscArray m1) (toAscArray m2)
142+
135143
instance showStrMap :: Show a => Show (StrMap a) where
136144
show m = "(fromFoldable " <> show (toArray m) <> ")"
137145

@@ -215,6 +223,11 @@ foreign import _collect :: forall a b . (String -> a -> b) -> StrMap a -> Array
215223
toUnfoldable :: forall f a. Unfoldable f => StrMap a -> f (Tuple String a)
216224
toUnfoldable = A.toUnfoldable <<< _collect Tuple
217225

226+
-- | Unfolds a map into a list of key/value pairs which is guaranteed to be
227+
-- | sorted by key
228+
toAscUnfoldable :: forall f a. Unfoldable f => StrMap a -> f (Tuple String a)
229+
toAscUnfoldable = A.toUnfoldable <<< A.sortWith fst <<< _collect Tuple
230+
218231
-- Internal
219232
toArray :: forall a. StrMap a -> Array (Tuple String a)
220233
toArray = _collect Tuple

test/Test/Data/StrMap.purs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Data.Maybe (Maybe(..))
1616
import Data.NonEmpty ((:|))
1717
import Data.StrMap as M
1818
import Data.Tuple (Tuple(..), fst)
19+
import Data.Traversable (sequence)
1920

2021
import Partial.Unsafe (unsafePartial)
2122

@@ -28,6 +29,11 @@ newtype TestStrMap v = TestStrMap (M.StrMap v)
2829
instance arbTestStrMap :: (Arbitrary v) => Arbitrary (TestStrMap v) where
2930
arbitrary = TestStrMap <<< (M.fromFoldable :: L.List (Tuple String v) -> M.StrMap v) <$> arbitrary
3031

32+
newtype SmallArray v = SmallArray (Array v)
33+
34+
instance arbSmallArray :: (Arbitrary v) => Arbitrary (SmallArray v) where
35+
arbitrary = SmallArray <$> Gen.resize 3 arbitrary
36+
3137
data Instruction k v = Insert k v | Delete k
3238

3339
instance showInstruction :: (Show k, Show v) => Show (Instruction k v) where
@@ -54,6 +60,9 @@ runInstructions instrs t0 = foldl step t0 instrs
5460
number :: Int -> Int
5561
number n = n
5662

63+
toAscArray :: forall a. M.StrMap a -> Array (Tuple String a)
64+
toAscArray = M.toAscUnfoldable
65+
5766
strMapTests :: forall eff. Eff (console :: CONSOLE, random :: RANDOM, exception :: EXCEPTION | eff) Unit
5867
strMapTests = do
5968
log "Test inserting into empty tree"
@@ -167,6 +176,19 @@ strMapTests = do
167176
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)
168177
in resultViaMapWithKey === resultViaLists
169178

179+
log "sequence works (for m = Array)"
180+
quickCheck \(TestStrMap mOfSmallArrays :: TestStrMap (SmallArray Int)) ->
181+
let m = (\(SmallArray a) -> a) <$> mOfSmallArrays
182+
Tuple keys values = A.unzip (toAscArray m)
183+
resultViaArrays = (M.fromFoldable <<< A.zip keys) <$> sequence values
184+
in A.sort (sequence m) === A.sort (resultViaArrays)
185+
186+
log "sequence works (for m = Maybe)"
187+
quickCheck \(TestStrMap m :: TestStrMap (Maybe Int)) ->
188+
let Tuple keys values = A.unzip (toAscArray m)
189+
resultViaArrays = (M.fromFoldable <<< A.zip keys) <$> sequence values
190+
in sequence m === resultViaArrays
191+
170192
log "Bug #63: accidental observable mutation in foldMap"
171193
quickCheck \(TestStrMap m) ->
172194
let lhs = go m

0 commit comments

Comments
 (0)