@@ -8,6 +8,7 @@ module Data.StrMap
88 ( StrMap (),
99 empty ,
1010 isEmpty ,
11+ size ,
1112 singleton ,
1213 insert ,
1314 lookup ,
@@ -24,60 +25,135 @@ module Data.StrMap
2425 map ,
2526 isSubmap ,
2627 fold ,
27- foldMaybe
28+ foldMap ,
29+ foldM ,
30+ foldMaybe ,
31+ all ,
32+
33+ thawST ,
34+ freezeST ,
35+ runST
2836 ) where
2937
3038import qualified Prelude as P
3139
40+ import Control.Monad.Eff (Eff (), runPure )
41+ import qualified Control.Monad.ST as ST
3242import qualified Data.Array as A
3343import Data.Maybe
3444import Data.Function
3545import Data.Tuple
36- import Data.Foldable (foldl )
46+ import Data.Foldable (Foldable , foldl , foldr , for_ )
47+ import Data.Monoid
48+ import Data.Monoid.All
49+ import qualified Data.StrMap.ST as SM
3750
3851foreign import data StrMap :: * -> *
3952
40- foreign import _foldStrMap
41- " function _foldStrMap(m, z0, f) {\
42- \ var z = z0;\
43- \ for (var k in m) {\
44- \ if (m.hasOwnProperty(k)) z = f(z)(k)(m[k]);\
45- \ }\
46- \ return z;\
47- \}" :: forall v z . Fn3 (StrMap v ) z (z -> String -> v -> z ) z
48-
49- fold :: forall a z . (z -> String -> a -> z ) -> z -> (StrMap a ) -> z
50- fold f z m = runFn3 _foldStrMap m z f
53+ foreign import _copy " " "
54+ function _copy(m) {
55+ var r = {};
56+ for (var k in m)
57+ r[k] = m[k]
58+ return r;
59+ }" " " :: forall a . StrMap a -> StrMap a
60+
61+ foreign import _copyEff " " "
62+ function _copyEff(m) {
63+ return function () {
64+ return _copy(m);
65+ };
66+ }" " " :: forall a b h r . a -> Eff (st :: ST.ST h | r ) b
67+
68+ thawST :: forall a h r . StrMap a -> Eff (st :: ST.ST h | r ) (SM.STStrMap h a )
69+ thawST = _copyEff
70+
71+ freezeST :: forall a h r . SM.STStrMap h a -> Eff (st :: ST.ST h | r ) (StrMap a )
72+ freezeST = _copyEff
73+
74+ foreign import runST " " "
75+ function runST(f) {
76+ return f;
77+ }" " " :: forall a r . (forall h . Eff (st :: ST.ST h | r ) (SM.STStrMap h a )) -> Eff r (StrMap a )
78+
79+ pureST :: forall a b . (forall h e . Eff (st :: ST.ST h | e ) (SM.STStrMap h a )) -> StrMap a
80+ pureST f = runPure (runST f)
81+
82+ mutate :: forall a b . (forall h e . SM.STStrMap h a -> Eff (st :: ST.ST h | e ) b ) -> StrMap a -> StrMap a
83+ mutate f m = pureST (do
84+ s <- thawST m
85+ f s
86+ P .return s)
5187
5288foreign import _fmapStrMap
5389 " function _fmapStrMap(m0, f) {\
5490 \ var m = {};\
5591 \ for (var k in m0) {\
56- \ if (m0.hasOwnProperty(k)) m[k] = f(m0[k]);\
92+ \ m[k] = f(m0[k]);\
5793 \ }\
5894 \ return m;\
5995 \}" :: forall a b . Fn2 (StrMap a ) (a -> b ) (StrMap b )
6096
6197instance functorStrMap :: P.Functor StrMap where
6298 (<$>) f m = runFn2 _fmapStrMap m f
6399
100+ foreign import _foldM
101+ " function _foldM(bind) {\
102+ \ return function(f) {\
103+ \ return function (mz) {\
104+ \ return function (m) {\
105+ \ var k;\
106+ \ function g(z) {\
107+ \ return f(z)(k)(m[k]);\
108+ \ }\
109+ \ for (k in m)\
110+ \ mz = bind(mz)(g);\
111+ \ return mz;\
112+ \ };\
113+ \ };\
114+ \ };\
115+ \}" :: forall a m z . (m -> (z -> m ) -> m ) -> (z -> String -> a -> m ) -> m -> StrMap a -> m
116+
117+ fold :: forall a z . (z -> String -> a -> z ) -> z -> StrMap a -> z
118+ fold = _foldM (P .(#))
119+
120+ foldMap :: forall a m . (Monoid m ) => (String -> a -> m ) -> StrMap a -> m
121+ foldMap f = fold (\acc k v -> acc P .<> f k v) mempty
122+
123+ foldM :: forall a m z . (P.Monad m ) => (z -> String -> a -> m z ) -> z -> StrMap a -> m z
124+ foldM f z = _foldM P .(>>=) f (P .pure z)
125+
126+ instance foldableStrMap :: Foldable StrMap where
127+ foldl f = fold (\z _ -> f z)
128+ foldr f z m = foldr f z (values m)
129+ foldMap f = foldMap (P .const f)
130+
131+ -- Unfortunately the above are not short-circuitable (consider using purescript-machines)
132+ -- so we need special cases:
133+
64134foreign import _foldSCStrMap
65- " function _foldSCStrMap(m, z0, f, fromMaybe) { \
66- \ var z = z0; \
135+ " function _foldSCStrMap(m, z, f, fromMaybe) { \
67136 \ for (var k in m) { \
68- \ if (m.hasOwnProperty(k)) { \
69- \ var maybeR = f(z)(k)(m[k]); \
70- \ var r = fromMaybe(null)(maybeR); \
71- \ if (r === null) return z; \
72- \ else z = r; \
73- \ } \
137+ \ var maybeR = f(z)(k)(m[k]); \
138+ \ var r = fromMaybe(null)(maybeR); \
139+ \ if (r === null) return z; \
140+ \ else z = r; \
74141 \ } \
75142 \ return z; \
76143 \}" :: forall a z . Fn4 (StrMap a ) z (z -> String -> a -> Maybe z ) (forall a . a -> Maybe a -> a ) z
77144
78- foldMaybe :: forall a z . (z -> String -> a -> Maybe z ) -> z -> ( StrMap a ) -> z
145+ foldMaybe :: forall a z . (z -> String -> a -> Maybe z ) -> z -> StrMap a -> z
79146foldMaybe f z m = runFn4 _foldSCStrMap m z f fromMaybe
80147
148+ foreign import all
149+ " function all(f) {\
150+ \ return function (m) {\
151+ \ for (var k in m)\
152+ \ if (!f(k)(m[k])) return false;\
153+ \ return true;\
154+ \ };\
155+ \}" :: forall a . (String -> a -> Boolean ) -> StrMap a -> Boolean
156+
81157instance eqStrMap :: (P.Eq a ) => P.Eq (StrMap a ) where
82158 (==) m1 m2 = (isSubmap m1 m2) P .&& (isSubmap m2 m1)
83159 (/=) m1 m2 = P .not (m1 P .== m2)
@@ -88,53 +164,39 @@ instance showStrMap :: (P.Show a) => P.Show (StrMap a) where
88164foreign import empty " var empty = {};" :: forall a . StrMap a
89165
90166isSubmap :: forall a . (P.Eq a ) => StrMap a -> StrMap a -> Boolean
91- isSubmap m1 m2 = foldMaybe f true m1 where
92- f acc k v = if (P .not acc) then (Nothing :: Maybe Boolean )
93- else Just P .$ acc P .&& (maybe false (\v0 -> v0 P .== v) (lookup k m2))
167+ isSubmap m1 m2 = all f m1 where
168+ f k v = runFn4 _lookup false (P .(==) v) k m2
94169
95170isEmpty :: forall a . StrMap a -> Boolean
96- isEmpty m = size m P .== 0
171+ isEmpty = all (\_ _ -> false )
97172
98173foreign import size " function size(m) {\
99174 \ var s = 0;\
100175 \ for (var k in m) {\
101- \ if (m.hasOwnProperty(k)) ++s;\
176+ \ ++s;\
102177 \ }\
103178 \ return s;\
104179 \}" :: forall a . StrMap a -> Number
105180
106181singleton :: forall a . String -> a -> StrMap a
107- singleton k v = insert k v empty
182+ singleton k v = pureST (do
183+ s <- SM .new
184+ SM .poke s k v
185+ P .return s)
108186
109187foreign import _lookup
110- " function _lookup(m, k, yes, no) { \
111- \ if (m[k] !== undefined) return yes(m[k]); \
112- \ else return no; \
113- \}" :: forall a z . Fn4 (StrMap a ) String (a -> z ) z z
188+ " function _lookup(no, yes, k, m) {\
189+ \ return k in m ? yes(m[k]) : no;\
190+ \}" :: forall a z . Fn4 z (a -> z ) String (StrMap a ) z
114191
115192lookup :: forall a . String -> StrMap a -> Maybe a
116- lookup k m = runFn4 _lookup m k Just Nothing
193+ lookup = runFn4 _lookup Nothing Just
117194
118195member :: forall a . String -> StrMap a -> Boolean
119- member k m = isJust (k `lookup` m)
120-
121- foreign import _cloneStrMap
122- " function _cloneStrMap(m0) { \
123- \ var m = {}; \
124- \ for (var k in m0) {\
125- \ if (m0.hasOwnProperty(k)) m[k] = m0[k];\
126- \ }\
127- \ return m;\
128- \}" :: forall a . (StrMap a ) -> (StrMap a )
129-
130- foreign import _unsafeInsertStrMap
131- " function _unsafeInsertStrMap(m, k, v) { \
132- \ m[k] = v; \
133- \ return m; \
134- \}" :: forall a . Fn3 (StrMap a ) String a (StrMap a )
196+ member = runFn4 _lookup false (P .const true )
135197
136198insert :: forall a . String -> a -> StrMap a -> StrMap a
137- insert k v m = runFn3 _unsafeInsertStrMap (_cloneStrMap m) k v
199+ insert k v = mutate (\s -> SM .poke s k v)
138200
139201foreign import _unsafeDeleteStrMap
140202 " function _unsafeDeleteStrMap(m, k) { \
@@ -143,7 +205,7 @@ foreign import _unsafeDeleteStrMap
143205 \}" :: forall a . Fn2 (StrMap a ) String (StrMap a )
144206
145207delete :: forall a . String -> StrMap a -> StrMap a
146- delete k m = runFn2 _unsafeDeleteStrMap (_cloneStrMap m) k
208+ delete k = mutate (\s -> SM .delete s k)
147209
148210alter :: forall a . (Maybe a -> Maybe a ) -> String -> StrMap a -> StrMap a
149211alter f k m = case f (k `lookup` m) of
@@ -153,26 +215,42 @@ alter f k m = case f (k `lookup` m) of
153215update :: forall a . (a -> Maybe a ) -> String -> StrMap a -> StrMap a
154216update f k m = alter (maybe Nothing f) k m
155217
156- toList :: forall a . StrMap a -> [Tuple String a ]
157- toList m = fold f [] m where
158- f acc k v = acc P .++ [Tuple k v]
159-
160218fromList :: forall a . [Tuple String a ] -> StrMap a
161- fromList = foldl (\m (Tuple k v) -> insert k v m) empty
219+ fromList l = pureST (do
220+ s <- SM .new
221+ for_ l (\(Tuple k v) -> SM .poke s k v)
222+ P .return s)
223+
224+ foreign import _collect
225+ " function _collect(f) {\
226+ \ return function (m) {\
227+ \ var r = [];\
228+ \ for (var k in m)\
229+ \ r.push(f(k)(m[k]));\
230+ \ return r;\
231+ \ };\
232+ \}" :: forall a b . (String -> a -> b ) -> StrMap a -> [b ]
162233
163- keys :: forall a . StrMap a -> [String ]
164- keys m = fold f [] m where
165- f acc k v = acc P .++ [k]
234+ toList :: forall a . StrMap a -> [Tuple String a ]
235+ toList = _collect Tuple
236+
237+ foreign import keys
238+ " var keys = Object.keys || _collect(function (k) {\
239+ \ return function () { return k; };\
240+ \});" :: forall a . StrMap a -> [String ]
166241
167242values :: forall a . StrMap a -> [a ]
168- values m = fold f [] m where
169- f acc k v = acc P .++ [v]
243+ values = _collect (\_ v -> v)
170244
245+ -- left-biased
171246union :: forall a . StrMap a -> StrMap a -> StrMap a
172- union m1 m2 = foldl (\m ( Tuple k v) -> insert k v m) m2 (toList m1 )
247+ union m = mutate (\s -> foldM SM .poke s m )
173248
174249unions :: forall a . [StrMap a ] -> StrMap a
175250unions = foldl union empty
176251
177252map :: forall a b . (a -> b ) -> StrMap a -> StrMap b
178- map = P .(<$>)
253+ map = P .(<$>)
254+
255+ instance semigroupStrMap :: (P.Semigroup a ) => P.Semigroup (StrMap a ) where
256+ (<>) m1 m2 = mutate (\s -> foldM (\s k v2 -> SM .poke s k (runFn4 _lookup v2 (\v1 -> v1 P .<> v2) k m2)) s m1) m2
0 commit comments