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, id, seq)
31 import qualified Hcompta.Lib.Strict as Strict ()
37 = TreeMap (Map k (Node k x))
38 deriving (Data, Eq, Show, Typeable)
40 instance (Ord k, Monoid v) => Monoid (TreeMap k v) where
42 mappend = union mappend
43 -- mconcat = Data.List.foldr mappend mempty
44 instance Ord k => Functor (TreeMap k) where
45 fmap f (TreeMap m) = TreeMap $ fmap (fmap f) m
46 instance Ord k => Foldable (TreeMap k) where
47 foldMap f (TreeMap m) = foldMap (foldMap f) m
48 instance Ord k => Traversable (TreeMap k) where
49 traverse f (TreeMap m) = TreeMap <$> traverse (traverse f) m
50 instance (Ord k, NFData k, NFData x) => NFData (TreeMap k x) where
51 rnf (TreeMap m) = rnf m
55 -- | A 'Path' is a non-empty list of 'Map' keys.
56 type Path k = NonEmpty k
58 path :: k -> [k] -> Path k
62 list = Data.List.NonEmpty.toList
64 reverse :: Path k -> Path k
65 reverse = Data.List.NonEmpty.reverse
71 { node_size :: !Int -- ^ The number of non-'Strict.Nothing' 'node_value's reachable from this 'Node'.
72 , node_value :: !(Strict.Maybe x) -- ^ Some value, or 'Strict.Nothing' if this 'Node' is intermediary.
73 , node_descendants :: !(TreeMap k x) -- ^ Descendants 'Node's.
74 } deriving (Data, Eq, Show, Typeable)
77 instance (Ord k, Monoid v) => Monoid (Node k v) where
80 { node_value = Strict.Nothing
82 , node_descendants = TreeMap mempty
85 Node{node_value=x0, node_descendants=m0}
86 Node{node_value=x1, node_descendants=m1} =
87 let m = union const m0 m1 in
88 let x = x0 `mappend` x1 in
91 , node_size = size m + Strict.maybe 0 (const 1) x
92 , node_descendants = union const m0 m1
94 -- mconcat = Data.List.foldr mappend mempty
95 instance Ord k => Functor (Node k) where
96 fmap f Node{node_value=x, node_descendants=m, node_size} =
98 { node_value = fmap f x
99 , node_descendants = map f m
102 instance Ord k => Foldable (Node k) where
103 foldMap f Node{node_value=Strict.Nothing, node_descendants=TreeMap m} =
104 foldMap (foldMap f) m
105 foldMap f Node{node_value=Strict.Just x, node_descendants=TreeMap m} =
106 f x `mappend` foldMap (foldMap f) m
107 instance Ord k => Traversable (Node k) where
108 traverse f Node{node_value=Strict.Nothing, node_descendants=TreeMap m, node_size} =
109 Node node_size <$> pure Strict.Nothing <*> (TreeMap <$> traverse (traverse f) m)
110 traverse f Node{node_value=Strict.Just x, node_descendants=TreeMap m, node_size} =
111 Node node_size <$> (Strict.Just <$> f x) <*> (TreeMap <$> traverse (traverse f) m)
112 instance (Ord k, NFData k, NFData x) => NFData (Node k x) where
113 rnf (Node s v d) = rnf s `seq` rnf v `seq` rnf d
117 -- | Return the empty 'TreeMap'.
118 empty :: Ord k => TreeMap k x
119 empty = TreeMap Data.Map.empty
121 -- | Return a 'TreeMap' only mapping the given 'Path' to the given value.
122 singleton :: Ord k => Path k -> x -> TreeMap k x
123 singleton ks x = insert const ks x empty
125 -- | Return a 'Node' only containing the given value.
126 leaf :: Ord k => x -> Node k x
129 { node_value = Strict.Just x
130 , node_descendants = empty
134 -- | Return the given 'TreeMap' associating the given 'Path' with the given value,
135 -- merging values if the given 'TreeMap' already associates the given 'Path'
136 -- with a non-'Strict.Nothing' 'node_value'.
137 insert :: Ord k => (x -> x -> x) -> Path k -> x -> TreeMap k x -> TreeMap k x
138 insert merge (k:|[]) x (TreeMap m) =
141 (\_ Node{node_value = x1, node_descendants = m1, node_size = s1} ->
143 { node_value = Strict.maybe (Strict.Just x) (Strict.Just . merge x) x1
144 , node_descendants = m1
145 , node_size = Strict.maybe (s1 + 1) (const s1) x1
148 insert merge (k:|k':ks) x (TreeMap m) =
151 (\_ Node{node_value = x1, node_descendants = m1} ->
152 let m' = insert merge (path k' ks) x $ m1 in
153 let s' = size m' + Strict.maybe 0 (const 1) x1 in
154 Node{node_value=x1, node_descendants=m', node_size=s'})
157 { node_value = Strict.Nothing
158 , node_descendants = insert merge (path k' ks) x empty
163 -- | Return a 'TreeMap' associating for each tuple of the given list
164 -- the 'Path' to the value,
165 -- merging values of identical 'Path's (in respective order).
166 from_List :: Ord k => (x -> x -> x) -> [(Path k, x)] -> TreeMap k x
167 from_List merge = Data.List.foldl (\acc (p, x) -> insert merge p x acc) empty
169 -- | Return a 'TreeMap' associating for each key and value of the given 'Map'
170 -- the 'Path' to the value,
171 -- merging values of identical 'Path's (in respective order).
172 from_Map :: Ord k => (x -> x -> x) -> Map (Path k) x -> TreeMap k x
173 from_Map merge = Data.Map.foldlWithKey (\acc p x -> insert merge p x acc) empty
177 -- | Return the 'Map' in the given 'TreeMap'.
178 nodes :: Ord k => TreeMap k x -> Map k (Node k x)
179 nodes (TreeMap m) = m
181 -- | Return 'True' iif. the given 'TreeMap' is 'empty'.
182 null :: Ord k => TreeMap k x -> Bool
183 null (TreeMap m) = Data.Map.null m
185 -- | Return the number of non-'Strict.Nothing' 'node_value's in the given 'TreeMap'.
187 -- * Complexity: O(r) where r is the size of the root 'Map'.
188 size :: Ord k => TreeMap k x -> Int
189 size = Data.Map.foldr ((+) . node_size) 0 . nodes
193 -- | Return the value (if any) associated with the given 'Path'.
194 find :: Ord k => Path k -> TreeMap k x -> Strict.Maybe x
195 find (k:|[]) (TreeMap m) = maybe Strict.Nothing node_value $ Data.Map.lookup k m
196 find (k:|k':ks) (TreeMap m) =
197 maybe Strict.Nothing (find (path k' ks) . node_descendants) $
200 -- | Return the values (if any) associated with the prefixes of the given 'Path' (included).
201 find_along :: Ord k => Path k -> TreeMap k x -> [x]
202 find_along p (TreeMap tm) =
205 go :: Ord k => [k] -> Map k (Node k x) -> [x]
208 case Data.Map.lookup k m of
211 Strict.maybe id (:) (node_value node) $
212 go ks $ nodes (node_descendants node)
216 -- | Return a 'TreeMap' associating the same 'Path's as both given 'TreeMap's,
217 -- merging values (in respective order) when a 'Path' leads
218 -- to a non-'Strict.Nothing' 'node_value' in both given 'TreeMap's.
219 union :: Ord k => (x -> x -> x) -> TreeMap k x -> TreeMap k x -> TreeMap k x
220 union merge (TreeMap tm0) (TreeMap tm1) =
223 (\Node{node_value=x0, node_descendants=m0}
224 Node{node_value=x1, node_descendants=m1} ->
225 let m = union merge m0 m1 in
226 let x = Strict.maybe x1 (\x0' -> Strict.maybe (Strict.Just x0') (Strict.Just . merge x0') x1) x0 in
229 , node_descendants = m
230 , node_size = size m + Strict.maybe 0 (const 1) x
234 -- | Return the 'union' of the given 'TreeMap's.
236 -- NOTE: use 'Data.List.foldl'' to reduce demand on the control-stack.
237 unions :: Ord k => (x -> x -> x) -> [TreeMap k x] -> TreeMap k x
238 unions merge = Data.List.foldl' (union merge) empty
240 -- foldl' :: (a -> b -> a) -> a -> [b] -> a
244 -- go z (x:xs) = z `seq` go (f z x) xs
248 -- | Return the given 'TreeMap' with each non-'Strict.Nothing' 'node_value'
249 -- mapped by the given function.
250 map :: Ord k => (x -> y) -> TreeMap k x -> TreeMap k y
254 (\n@Node{node_value=x, node_descendants=m} ->
255 n{ node_value = fmap f x
256 , node_descendants = map f m
260 -- | Return the given 'TreeMap' with each 'Path' section
261 -- and each non-'Strict.Nothing' 'node_value'
262 -- mapped by the given functions.
264 -- WARNING: the function mapping 'Path' sections must be monotonic,
265 -- like in 'Data.Map.mapKeysMonotonic'.
266 map_monotonic :: (Ord k, Ord l) => (k -> l) -> (x -> y) -> TreeMap k x -> TreeMap l y
267 map_monotonic fk fx =
269 Data.Map.mapKeysMonotonic fk .
271 (\n@Node{node_value=x, node_descendants=m} ->
272 n{ node_value = fmap fx x
273 , node_descendants = map_monotonic fk fx m
277 -- | Return the given 'TreeMap' with each 'node_value'
278 -- mapped by the given function supplied with
279 -- the already mapped 'node_descendants' of the current 'Node'.
280 map_by_depth_first :: Ord k => (TreeMap k y -> Strict.Maybe x -> y) -> TreeMap k x -> TreeMap k y
281 map_by_depth_first f =
284 (\Node{node_value, node_descendants} ->
285 let m = map_by_depth_first f node_descendants in
287 { node_value = Strict.Just $ f m node_value
288 , node_descendants = m
289 , node_size = size m + 1
295 alterl_path :: Ord k => (Strict.Maybe x -> Strict.Maybe x) -> Path k -> TreeMap k x -> TreeMap k x
300 => (Strict.Maybe x -> Strict.Maybe x) -> [k]
301 -> TreeMap k x -> TreeMap k x
303 go f (k:p) (TreeMap m) =
309 Just Node{node_value=v, node_descendants=d} -> (v, d)
310 Nothing -> (Strict.Nothing, empty) in
312 let gm = go f p cm in
313 case (fx, size gm) of
314 (Strict.Nothing, 0) -> Nothing
318 , node_descendants = gm
325 -- | Return the given accumulator folded by the given function
326 -- applied on non-'Strict.Nothing' 'node_value's
327 -- from left to right through the given 'TreeMap'.
328 foldl_with_Path :: Ord k => (a -> Path k -> x -> a) -> a -> TreeMap k x -> a
333 => [k] -> (a -> Path k -> x -> a)
334 -> a -> TreeMap k x -> a
335 foldp p fct a (TreeMap m) =
336 Data.Map.foldlWithKey
337 (\acc k Node{node_value, node_descendants} ->
338 let acc' = Strict.maybe acc (fct acc (reverse $ path k p)) node_value in
339 foldp (k:p) fct acc' node_descendants) 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 left to right through the given 'TreeMap'.
344 foldl_with_Path_and_Node :: Ord k => (a -> Node k x -> Path k -> x -> a) -> a -> TreeMap k x -> a
345 foldl_with_Path_and_Node =
349 => [k] -> (a -> Node k x -> Path k -> x -> a)
350 -> a -> TreeMap k x -> a
351 foldp p fct a (TreeMap m) =
352 Data.Map.foldlWithKey
353 (\acc k n@Node{node_value, node_descendants} ->
354 let acc' = Strict.maybe acc (fct acc n (reverse $ path k p)) node_value in
355 foldp (k:p) fct acc' node_descendants) a m
357 -- | Return the given accumulator folded by the given function
358 -- applied on non-'Strict.Nothing' 'node_value's
359 -- from right to left through the given 'TreeMap'.
360 foldr_with_Path :: Ord k => (Path k -> x -> a -> a) -> a -> TreeMap k x -> a
365 => [k] -> (Path k -> x -> a -> a)
366 -> a -> TreeMap k x -> a
367 foldp p fct a (TreeMap m) =
368 Data.Map.foldrWithKey
369 (\k Node{node_value, node_descendants} acc ->
370 let acc' = foldp (k:p) fct acc node_descendants in
371 Strict.maybe acc' (\x -> fct (reverse $ path k p) x acc') node_value) a m
373 -- | Return the given accumulator folded by the given function
374 -- applied on non-'Strict.Nothing' 'Node's and 'node_value's
375 -- from right to left through the given 'TreeMap'.
376 foldr_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> a -> a) -> a -> TreeMap k x -> a
377 foldr_with_Path_and_Node =
381 => [k] -> (Node k x -> Path k -> x -> a -> a)
382 -> a -> TreeMap k x -> a
383 foldp p fct a (TreeMap m) =
384 Data.Map.foldrWithKey
385 (\k n@Node{node_value, node_descendants} acc ->
386 let acc' = foldp (k:p) fct acc node_descendants in
387 Strict.maybe acc' (\x -> fct n (reverse $ path k p) x acc') node_value) a m
389 -- | Return the given accumulator folded by the given function
390 -- applied on non-'Strict.Nothing' 'node_value's
391 -- from left to right along the given 'Path'.
392 foldl_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
397 => (Path k -> x -> a -> a) -> [k] -> [k]
398 -> TreeMap k x -> a -> a
400 go f p (k:n) (TreeMap t) a =
401 case Data.Map.lookup k t of
403 Just Node{node_value=v, node_descendants=d} ->
405 Strict.Nothing -> go f (k:p) n d a
406 Strict.Just x -> go f (k:p) n d (f (reverse $ path k p) x a)
408 -- | Return the given accumulator folded by the given function
409 -- applied on non-'Strict.Nothing' 'node_value's
410 -- from right to left along the given 'Path'.
411 foldr_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
416 => (Path k -> x -> a -> a) -> [k] -> [k]
417 -> TreeMap k x -> a -> a
419 go f p (k:n) (TreeMap t) a =
420 case Data.Map.lookup k t of
422 Just Node{node_value=v, node_descendants=d} ->
424 Strict.Nothing -> go f (k:p) n d a
425 Strict.Just x -> f (reverse $ path k p) x $ go f (k:p) n d a
429 -- | Return a 'Map' associating each 'Path'
430 -- leading to a non-'Strict.Nothing' 'node_value' in the given 'TreeMap',
431 -- with its value mapped by the given function.
432 flatten :: Ord k => (x -> y) -> TreeMap k x -> Map (Path k) y
433 flatten = flatten_with_Path . const
435 -- | Like 'flatten' but with also the current 'Path' given to the mapping function.
436 flatten_with_Path :: Ord k => (Path k -> x -> y) -> TreeMap k x -> Map (Path k) y
441 => [k] -> (Path k -> x -> y)
444 flat_map p f (TreeMap m) =
447 Data.Map.mapKeysMonotonic (reverse . flip path p) $
448 Data.Map.mapMaybeWithKey (\k Node{node_value} ->
450 Strict.Nothing -> Nothing
451 Strict.Just x -> Just $ f (reverse $ path k p) x) m
453 Data.Map.foldrWithKey
454 (\k -> (:) . flat_map (k:p) f . node_descendants)
459 -- | Return the given 'TreeMap'
460 -- keeping only its non-'Strict.Nothing' 'node_value's
461 -- passing the given predicate.
462 filter :: Ord k => (x -> Bool) -> TreeMap k x -> TreeMap k x
465 (\_p x -> if f x then Strict.Just x else Strict.Nothing)
467 -- | Like 'filter' but with also the current 'Path' given to the predicate.
468 filter_with_Path :: Ord k => (Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
471 (\p x -> if f p x then Strict.Just x else Strict.Nothing)
473 -- | Like 'filter_with_Path' but with also the current 'Node' given to the predicate.
474 filter_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
475 filter_with_Path_and_Node f =
476 map_Maybe_with_Path_and_Node
477 (\n p x -> if f n p x then Strict.Just x else Strict.Nothing)
479 -- | Return the given 'TreeMap'
480 -- mapping its non-'Strict.Nothing' 'node_value's
481 -- and keeping only the non-'Strict.Nothing' results.
482 map_Maybe :: Ord k => (x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
483 map_Maybe = map_Maybe_with_Path . const
485 -- | Like 'map_Maybe' but with also the current 'Path' given to the predicate.
486 map_Maybe_with_Path :: Ord k => (Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
487 map_Maybe_with_Path = map_Maybe_with_Path_and_Node . const
489 -- | Like 'map_Maybe_with_Path' but with also the current 'Node' given to the predicate.
490 map_Maybe_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
491 map_Maybe_with_Path_and_Node =
495 => [k] -> (Node k x -> Path k -> x -> Strict.Maybe y)
498 go p test (TreeMap m) =
500 Data.Map.mapMaybeWithKey
501 (\k node@Node{node_value=v, node_descendants=ns} ->
502 let node_descendants = go (k:p) test ns in
503 let node_size = size node_descendants in
506 let node_value = test node (reverse $ path k p) x in
508 Strict.Nothing | null node_descendants -> Nothing
509 Strict.Nothing -> Just Node{node_value, node_descendants, node_size=1 + node_size}
510 Strict.Just _ -> Just Node{node_value, node_descendants, node_size}
512 if null node_descendants
514 else Just Node{node_value=Strict.Nothing, node_descendants, node_size}