1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE NamedFieldPuns #-}
4 -- | This module implements a strict 'TreeMap',
5 -- which is like a 'Map'
6 -- but whose key is now a 'NonEmpty' list of 'Map' keys (a 'Path')
7 -- enabling the possibility to gather mapped values
8 -- by 'Path' prefixes (inside a 'Node').
9 module Hcompta.Lib.TreeMap where
11 import Control.Applicative ((<$>), (<*>), pure)
12 import Control.DeepSeq (NFData(..))
15 import Data.Data (Data)
16 import Data.Foldable (Foldable, foldMap)
17 import Data.Functor (Functor(..))
18 import Data.Ord (Ord(..))
19 import qualified Data.List
20 import qualified Data.List.NonEmpty
21 import Data.List.NonEmpty (NonEmpty(..))
22 import Data.Map.Strict (Map)
23 import qualified Data.Map.Strict as Data.Map
24 import Data.Maybe (Maybe(..), maybe)
25 import Data.Monoid (Monoid(..))
26 import qualified Data.Strict.Maybe as Strict
27 import Data.Traversable (Traversable(..))
28 import Data.Typeable (Typeable)
29 import Prelude (($), (.), Int, Num(..), Show, const, flip, seq)
31 import qualified Hcompta.Lib.Strict as Strict ()
36 = TreeMap (Map k (Node k x))
37 deriving (Data, Eq, Show, Typeable)
39 instance (Ord k, Monoid v) => Monoid (TreeMap k v) where
41 mappend = union mappend
42 -- mconcat = Data.List.foldr mappend mempty
43 instance Ord k => Functor (TreeMap k) where
44 fmap f (TreeMap m) = TreeMap $ fmap (fmap f) m
45 instance Ord k => Foldable (TreeMap k) where
46 foldMap f (TreeMap m) = foldMap (foldMap f) m
47 instance Ord k => Traversable (TreeMap k) where
48 traverse f (TreeMap m) = TreeMap <$> traverse (traverse f) m
49 instance (Ord k, NFData k, NFData x) => NFData (TreeMap k x) where
50 rnf (TreeMap m) = rnf m
54 -- | A 'Path' is a non-empty list of 'Map' keys.
55 type Path k = NonEmpty k
57 path :: k -> [k] -> Path k
61 list = Data.List.NonEmpty.toList
63 reverse :: Path k -> Path k
64 reverse = Data.List.NonEmpty.reverse
70 { node_size :: !Int -- ^ The number of non-'Strict.Nothing' 'node_value's reachable from this 'Node'.
71 , node_value :: !(Strict.Maybe x) -- ^ Some value, or 'Strict.Nothing' if this 'Node' is intermediary.
72 , node_descendants :: !(TreeMap k x) -- ^ Descendants 'Node's.
73 } deriving (Data, Eq, Show, Typeable)
76 instance (Ord k, Monoid v) => Monoid (Node k v) where
79 { node_value = Strict.Nothing
81 , node_descendants = TreeMap mempty
84 Node{node_value=x0, node_descendants=m0}
85 Node{node_value=x1, node_descendants=m1} =
86 let m = union const m0 m1 in
87 let x = x0 `mappend` x1 in
90 , node_size = size m + Strict.maybe 0 (const 1) x
91 , node_descendants = union const m0 m1
93 -- mconcat = Data.List.foldr mappend mempty
94 instance Ord k => Functor (Node k) where
95 fmap f Node{node_value=x, node_descendants=m, node_size} =
97 { node_value = fmap f x
98 , node_descendants = Hcompta.Lib.TreeMap.map f m
101 instance Ord k => Foldable (Node k) where
102 foldMap f Node{node_value=Strict.Nothing, node_descendants=TreeMap m} =
103 foldMap (foldMap f) m
104 foldMap f Node{node_value=Strict.Just x, node_descendants=TreeMap m} =
105 f x `mappend` foldMap (foldMap f) m
106 instance Ord k => Traversable (Node k) where
107 traverse f Node{node_value=Strict.Nothing, node_descendants=TreeMap m, node_size} =
108 Node node_size <$> pure Strict.Nothing <*> (TreeMap <$> traverse (traverse f) m)
109 traverse f Node{node_value=Strict.Just x, node_descendants=TreeMap m, node_size} =
110 Node node_size <$> (Strict.Just <$> f x) <*> (TreeMap <$> traverse (traverse f) m)
111 instance (Ord k, NFData k, NFData x) => NFData (Node k x) where
112 rnf (Node s v d) = rnf s `seq` rnf v `seq` rnf d
116 -- | Return the empty 'TreeMap'.
118 empty = TreeMap Data.Map.empty
120 -- | Return a 'TreeMap' only mapping the given 'Path' to the given value.
121 singleton :: Ord k => Path k -> x -> TreeMap k x
122 singleton ks x = insert const ks x empty
124 -- | Return a 'Node' only containing the given value.
125 leaf :: Ord k => x -> Node k x
128 { node_value = Strict.Just x
129 , node_descendants = empty
133 -- | Return the given 'TreeMap' associating the given 'Path' with the given value,
134 -- merging values if the given 'TreeMap' already associates the given 'Path'
135 -- with a non-'Strict.Nothing' 'node_value'.
136 insert :: Ord k => (x -> x -> x) -> Path k -> x -> TreeMap k x -> TreeMap k x
137 insert merge (k:|[]) x (TreeMap m) =
140 (\_ Node{node_value = x1, node_descendants = m1, node_size = s1} ->
142 { node_value = Strict.maybe (Strict.Just x) (Strict.Just . merge x) x1
143 , node_descendants = m1
144 , node_size = Strict.maybe (s1 + 1) (const s1) x1
147 insert merge (k:|k':ks) x (TreeMap m) =
150 (\_ Node{node_value = x1, node_descendants = m1} ->
151 let m' = insert merge (path k' ks) x $ m1 in
152 let s' = size m' + Strict.maybe 0 (const 1) x1 in
153 Node{node_value=x1, node_descendants=m', node_size=s'})
156 { node_value = Strict.Nothing
157 , node_descendants = insert merge (path k' ks) x empty
162 -- | Return a 'TreeMap' associating for each tuple of the given list
163 -- the 'Path' to the value,
164 -- merging values of identical 'Path's (in respective order).
165 from_List :: Ord k => (x -> x -> x) -> [(Path k, x)] -> TreeMap k x
166 from_List merge = Data.List.foldl (\acc (p, x) -> insert merge p x acc) empty
168 -- | Return a 'TreeMap' associating for each key and value of the given 'Map'
169 -- the 'Path' to the value,
170 -- merging values of identical 'Path's (in respective order).
171 from_Map :: Ord k => (x -> x -> x) -> Map (Path k) x -> TreeMap k x
172 from_Map merge = Data.Map.foldlWithKey (\acc p x -> insert merge p x acc) empty
176 -- | Return the 'Map' in the given 'TreeMap'.
177 nodes :: TreeMap k x -> Map k (Node k x)
178 nodes (TreeMap m) = m
180 -- | Return 'True' iif. the given 'TreeMap' is 'empty'.
181 null :: TreeMap k x -> Bool
182 null (TreeMap m) = Data.Map.null m
184 -- | Return the number of non-'Strict.Nothing' 'node_value's in the given 'TreeMap'.
186 -- * Complexity: O(r) where r is the size of the root 'Map'.
187 size :: Ord k => TreeMap k x -> Int
188 size = Data.Map.foldr ((+) . node_size) 0 . nodes
192 -- | Return the value (if any) associated with the given 'Path'.
193 find :: Ord k => Path k -> TreeMap k x -> Strict.Maybe x
194 find (k:|[]) (TreeMap m) = maybe Strict.Nothing node_value $ Data.Map.lookup k m
195 find (k:|k':ks) (TreeMap m) =
196 maybe Strict.Nothing (find (path k' ks) . node_descendants) $
201 -- | Return a 'TreeMap' associating the same 'Path's as both given 'TreeMap's,
202 -- merging values (in respective order) when a 'Path' leads
203 -- to a non-'Strict.Nothing' 'node_value' in both given 'TreeMap's.
204 union :: Ord k => (x -> x -> x) -> TreeMap k x -> TreeMap k x -> TreeMap k x
205 union merge (TreeMap tm0) (TreeMap tm1) =
208 (\Node{node_value=x0, node_descendants=m0}
209 Node{node_value=x1, node_descendants=m1} ->
210 let m = union merge m0 m1 in
211 let x = Strict.maybe x1 (\x0' -> Strict.maybe (Strict.Just x0') (Strict.Just . merge x0') x1) x0 in
214 , node_descendants = m
215 , node_size = size m + Strict.maybe 0 (const 1) x
219 -- | Return the 'union' of the given 'TreeMap's.
221 -- NOTE: use 'Data.List.foldl'' to reduce demand on the control-stack.
222 unions :: Ord k => (x -> x -> x) -> [TreeMap k x] -> TreeMap k x
223 unions merge = Data.List.foldl' (union merge) empty
225 -- foldl' :: (a -> b -> a) -> a -> [b] -> a
229 -- go z (x:xs) = z `seq` go (f z x) xs
233 -- | Return the given 'TreeMap' with each non-'Strict.Nothing' 'node_value'
234 -- mapped by the given function.
235 map :: Ord k => (x -> y) -> TreeMap k x -> TreeMap k y
239 (\n@Node{node_value=x, node_descendants=m} ->
240 n{ node_value=Strict.maybe Strict.Nothing (Strict.Just . f) x
241 , node_descendants=Hcompta.Lib.TreeMap.map f m
245 -- | Return the given 'TreeMap' with each 'node_value'
246 -- mapped by the given function supplied with
247 -- the already mapped 'node_descendants' of the current 'Node'.
248 map_by_depth_first :: Ord k => (TreeMap k y -> Strict.Maybe x -> y) -> TreeMap k x -> TreeMap k y
249 map_by_depth_first f =
252 (\Node{node_value, node_descendants} ->
253 let m = map_by_depth_first f node_descendants in
255 { node_value = Strict.Just $ f m node_value
256 , node_descendants = m
257 , node_size = size m + 1
263 alterl_path :: Ord k => (Strict.Maybe x -> Strict.Maybe x) -> Path k -> TreeMap k x -> TreeMap k x
268 => (Strict.Maybe x -> Strict.Maybe x) -> [k]
269 -> TreeMap k x -> TreeMap k x
271 go f (k:p) (TreeMap m) =
277 Just Node{node_value=v, node_descendants=d} -> (v, d)
278 Nothing -> (Strict.Nothing, empty) in
280 let gm = go f p cm in
281 case (fx, size gm) of
282 (Strict.Nothing, 0) -> Nothing
286 , node_descendants = gm
293 -- | Return the given accumulator folded by the given function
294 -- applied on non-'Strict.Nothing' 'node_value's
295 -- from left to right through the given 'TreeMap'.
296 foldl_with_Path :: Ord k => (a -> Path k -> x -> a) -> a -> TreeMap k x -> a
301 => [k] -> (a -> Path k -> x -> a)
302 -> a -> TreeMap k x -> a
303 foldp p fct a (TreeMap m) =
304 Data.Map.foldlWithKey
305 (\acc k Node{node_value, node_descendants} ->
306 let acc' = Strict.maybe acc (fct acc (reverse $ path k p)) node_value in
307 foldp (k:p) fct acc' node_descendants) a m
309 -- | Return the given accumulator folded by the given function
310 -- applied on non-'Strict.Nothing' 'Node's and 'node_value's
311 -- from left to right through the given 'TreeMap'.
312 foldl_with_Path_and_Node :: Ord k => (a -> Node k x -> Path k -> x -> a) -> a -> TreeMap k x -> a
313 foldl_with_Path_and_Node =
317 => [k] -> (a -> Node k x -> Path k -> x -> a)
318 -> a -> TreeMap k x -> a
319 foldp p fct a (TreeMap m) =
320 Data.Map.foldlWithKey
321 (\acc k n@Node{node_value, node_descendants} ->
322 let acc' = Strict.maybe acc (fct acc n (reverse $ path k p)) node_value in
323 foldp (k:p) fct acc' node_descendants) a m
325 -- | Return the given accumulator folded by the given function
326 -- applied on non-'Strict.Nothing' 'node_value's
327 -- from right to left through the given 'TreeMap'.
328 foldr_with_Path :: Ord k => (Path k -> x -> a -> a) -> a -> TreeMap k x -> a
333 => [k] -> (Path k -> x -> a -> a)
334 -> a -> TreeMap k x -> a
335 foldp p fct a (TreeMap m) =
336 Data.Map.foldrWithKey
337 (\k Node{node_value, node_descendants} acc ->
338 let acc' = foldp (k:p) fct acc node_descendants in
339 Strict.maybe acc' (\x -> fct (reverse $ path k p) x acc') node_value) a m
341 -- | Return the given accumulator folded by the given function
342 -- applied on non-'Strict.Nothing' 'Node's and 'node_value's
343 -- from right to left through the given 'TreeMap'.
344 foldr_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> a -> a) -> a -> TreeMap k x -> a
345 foldr_with_Path_and_Node =
349 => [k] -> (Node k x -> Path k -> x -> a -> a)
350 -> a -> TreeMap k x -> a
351 foldp p fct a (TreeMap m) =
352 Data.Map.foldrWithKey
353 (\k n@Node{node_value, node_descendants} acc ->
354 let acc' = foldp (k:p) fct acc node_descendants in
355 Strict.maybe acc' (\x -> fct n (reverse $ path k p) x acc') node_value) a m
357 -- | Return the given accumulator folded by the given function
358 -- applied on non-'Strict.Nothing' 'node_value's
359 -- from left to right along the given 'Path'.
360 foldl_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
365 => (Path k -> x -> a -> a) -> [k] -> [k]
366 -> TreeMap k x -> a -> a
368 go f p (k:n) (TreeMap t) a =
369 case Data.Map.lookup k t of
371 Just Node{node_value=v, node_descendants=d} ->
373 Strict.Nothing -> go f (k:p) n d a
374 Strict.Just x -> go f (k:p) n d (f (reverse $ path k p) x a)
376 -- | Return the given accumulator folded by the given function
377 -- applied on non-'Strict.Nothing' 'node_value's
378 -- from right to left along the given 'Path'.
379 foldr_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
384 => (Path k -> x -> a -> a) -> [k] -> [k]
385 -> TreeMap k x -> a -> a
387 go f p (k:n) (TreeMap t) a =
388 case Data.Map.lookup k t of
390 Just Node{node_value=v, node_descendants=d} ->
392 Strict.Nothing -> go f (k:p) n d a
393 Strict.Just x -> f (reverse $ path k p) x $ go f (k:p) n d a
397 -- | Return a 'Map' associating each 'Path'
398 -- leading to a non-'Strict.Nothing' 'node_value' in the given 'TreeMap',
399 -- with its value mapped by the given function.
400 flatten :: Ord k => (x -> y) -> TreeMap k x -> Map (Path k) y
401 flatten = flatten_with_Path . const
403 -- | Like 'flatten' but with also the current 'Path' given to the mapping function.
404 flatten_with_Path :: Ord k => (Path k -> x -> y) -> TreeMap k x -> Map (Path k) y
409 => [k] -> (Path k -> x -> y)
412 flat_map p f (TreeMap m) =
415 Data.Map.mapKeysMonotonic (reverse . flip path p) $
416 Data.Map.mapMaybeWithKey (\k Node{node_value} ->
418 Strict.Nothing -> Nothing
419 Strict.Just x -> Just $ f (reverse $ path k p) x) m
421 Data.Map.foldrWithKey
422 (\k -> (:) . flat_map (k:p) f . node_descendants)
427 -- | Return the given 'TreeMap'
428 -- keeping only its non-'Strict.Nothing' 'node_value's
429 -- passing the given predicate.
430 filter :: Ord k => (x -> Bool) -> TreeMap k x -> TreeMap k x
433 (\_p x -> if f x then Strict.Just x else Strict.Nothing)
435 -- | Like 'filter' but with also the current 'Path' given to the predicate.
436 filter_with_Path :: Ord k => (Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
439 (\p x -> if f p x then Strict.Just x else Strict.Nothing)
441 -- | Like 'filter_with_Path' but with also the current 'Node' given to the predicate.
442 filter_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
443 filter_with_Path_and_Node f =
444 map_Maybe_with_Path_and_Node
445 (\n p x -> if f n p x then Strict.Just x else Strict.Nothing)
447 -- | Return the given 'TreeMap'
448 -- mapping its non-'Strict.Nothing' 'node_value's
449 -- and keeping only the non-'Strict.Nothing' results.
450 map_Maybe :: Ord k => (x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
451 map_Maybe = map_Maybe_with_Path . const
453 -- | Like 'map_Maybe' but with also the current 'Path' given to the predicate.
454 map_Maybe_with_Path :: Ord k => (Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
455 map_Maybe_with_Path = map_Maybe_with_Path_and_Node . const
457 -- | Like 'map_Maybe_with_Path' but with also the current 'Node' given to the predicate.
458 map_Maybe_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
459 map_Maybe_with_Path_and_Node =
463 => [k] -> (Node k x -> Path k -> x -> Strict.Maybe y)
466 go p test (TreeMap m) =
468 Data.Map.mapMaybeWithKey
469 (\k node@Node{node_value=v, node_descendants=ns} ->
470 let node_descendants = go (k:p) test ns in
471 let node_size = size node_descendants in
474 let node_value = test node (reverse $ path k p) x in
476 Strict.Nothing | null node_descendants -> Nothing
477 Strict.Nothing -> Just Node{node_value, node_descendants, node_size=1 + node_size}
478 Strict.Just _ -> Just Node{node_value, node_descendants, node_size}
480 if null node_descendants
482 else Just Node{node_value=Strict.Nothing, node_descendants, node_size}