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 ()
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) $
199 -- | Return the values (if any) associated with the prefixes of the given 'Path' (included).
200 find_along :: Ord k => Path k -> TreeMap k x -> [x]
201 find_along p (TreeMap tm) =
204 go :: Ord k => [k] -> Map k (Node k x) -> [x]
207 case Data.Map.lookup k m of
210 Strict.maybe id (:) (node_value node) $
211 go ks $ nodes (node_descendants node)
215 -- | Return a 'TreeMap' associating the same 'Path's as both given 'TreeMap's,
216 -- merging values (in respective order) when a 'Path' leads
217 -- to a non-'Strict.Nothing' 'node_value' in both given 'TreeMap's.
218 union :: Ord k => (x -> x -> x) -> TreeMap k x -> TreeMap k x -> TreeMap k x
219 union merge (TreeMap tm0) (TreeMap tm1) =
222 (\Node{node_value=x0, node_descendants=m0}
223 Node{node_value=x1, node_descendants=m1} ->
224 let m = union merge m0 m1 in
225 let x = Strict.maybe x1 (\x0' -> Strict.maybe (Strict.Just x0') (Strict.Just . merge x0') x1) x0 in
228 , node_descendants = m
229 , node_size = size m + Strict.maybe 0 (const 1) x
233 -- | Return the 'union' of the given 'TreeMap's.
235 -- NOTE: use 'Data.List.foldl'' to reduce demand on the control-stack.
236 unions :: Ord k => (x -> x -> x) -> [TreeMap k x] -> TreeMap k x
237 unions merge = Data.List.foldl' (union merge) empty
239 -- foldl' :: (a -> b -> a) -> a -> [b] -> a
243 -- go z (x:xs) = z `seq` go (f z x) xs
247 -- | Return the given 'TreeMap' with each non-'Strict.Nothing' 'node_value'
248 -- mapped by the given function.
249 map :: Ord k => (x -> y) -> TreeMap k x -> TreeMap k y
253 (\n@Node{node_value=x, node_descendants=m} ->
254 n{ node_value=Strict.maybe Strict.Nothing (Strict.Just . f) x
255 , node_descendants=Hcompta.Lib.TreeMap.map f m
259 -- | Return the given 'TreeMap' with each 'node_value'
260 -- mapped by the given function supplied with
261 -- the already mapped 'node_descendants' of the current 'Node'.
262 map_by_depth_first :: Ord k => (TreeMap k y -> Strict.Maybe x -> y) -> TreeMap k x -> TreeMap k y
263 map_by_depth_first f =
266 (\Node{node_value, node_descendants} ->
267 let m = map_by_depth_first f node_descendants in
269 { node_value = Strict.Just $ f m node_value
270 , node_descendants = m
271 , node_size = size m + 1
277 alterl_path :: Ord k => (Strict.Maybe x -> Strict.Maybe x) -> Path k -> TreeMap k x -> TreeMap k x
282 => (Strict.Maybe x -> Strict.Maybe x) -> [k]
283 -> TreeMap k x -> TreeMap k x
285 go f (k:p) (TreeMap m) =
291 Just Node{node_value=v, node_descendants=d} -> (v, d)
292 Nothing -> (Strict.Nothing, empty) in
294 let gm = go f p cm in
295 case (fx, size gm) of
296 (Strict.Nothing, 0) -> Nothing
300 , node_descendants = gm
307 -- | Return the given accumulator folded by the given function
308 -- applied on non-'Strict.Nothing' 'node_value's
309 -- from left to right through the given 'TreeMap'.
310 foldl_with_Path :: Ord k => (a -> Path k -> x -> a) -> a -> TreeMap k x -> a
315 => [k] -> (a -> Path k -> x -> a)
316 -> a -> TreeMap k x -> a
317 foldp p fct a (TreeMap m) =
318 Data.Map.foldlWithKey
319 (\acc k Node{node_value, node_descendants} ->
320 let acc' = Strict.maybe acc (fct acc (reverse $ path k p)) node_value in
321 foldp (k:p) fct acc' node_descendants) a m
323 -- | Return the given accumulator folded by the given function
324 -- applied on non-'Strict.Nothing' 'Node's and 'node_value's
325 -- from left to right through the given 'TreeMap'.
326 foldl_with_Path_and_Node :: Ord k => (a -> Node k x -> Path k -> x -> a) -> a -> TreeMap k x -> a
327 foldl_with_Path_and_Node =
331 => [k] -> (a -> Node k x -> Path k -> x -> a)
332 -> a -> TreeMap k x -> a
333 foldp p fct a (TreeMap m) =
334 Data.Map.foldlWithKey
335 (\acc k n@Node{node_value, node_descendants} ->
336 let acc' = Strict.maybe acc (fct acc n (reverse $ path k p)) node_value in
337 foldp (k:p) fct acc' node_descendants) a m
339 -- | Return the given accumulator folded by the given function
340 -- applied on non-'Strict.Nothing' 'node_value's
341 -- from right to left through the given 'TreeMap'.
342 foldr_with_Path :: Ord k => (Path k -> x -> a -> a) -> a -> TreeMap k x -> a
347 => [k] -> (Path k -> x -> a -> a)
348 -> a -> TreeMap k x -> a
349 foldp p fct a (TreeMap m) =
350 Data.Map.foldrWithKey
351 (\k Node{node_value, node_descendants} acc ->
352 let acc' = foldp (k:p) fct acc node_descendants in
353 Strict.maybe acc' (\x -> fct (reverse $ path k p) x acc') node_value) a m
355 -- | Return the given accumulator folded by the given function
356 -- applied on non-'Strict.Nothing' 'Node's and 'node_value's
357 -- from right to left through the given 'TreeMap'.
358 foldr_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> a -> a) -> a -> TreeMap k x -> a
359 foldr_with_Path_and_Node =
363 => [k] -> (Node k x -> Path k -> x -> a -> a)
364 -> a -> TreeMap k x -> a
365 foldp p fct a (TreeMap m) =
366 Data.Map.foldrWithKey
367 (\k n@Node{node_value, node_descendants} acc ->
368 let acc' = foldp (k:p) fct acc node_descendants in
369 Strict.maybe acc' (\x -> fct n (reverse $ path k p) x acc') node_value) a m
371 -- | Return the given accumulator folded by the given function
372 -- applied on non-'Strict.Nothing' 'node_value's
373 -- from left to right along the given 'Path'.
374 foldl_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
379 => (Path k -> x -> a -> a) -> [k] -> [k]
380 -> TreeMap k x -> a -> a
382 go f p (k:n) (TreeMap t) a =
383 case Data.Map.lookup k t of
385 Just Node{node_value=v, node_descendants=d} ->
387 Strict.Nothing -> go f (k:p) n d a
388 Strict.Just x -> go f (k:p) n d (f (reverse $ path k p) x a)
390 -- | Return the given accumulator folded by the given function
391 -- applied on non-'Strict.Nothing' 'node_value's
392 -- from right to left along the given 'Path'.
393 foldr_path :: Ord k => (Path k -> x -> a -> a) -> Path k -> TreeMap k x -> a -> a
398 => (Path k -> x -> a -> a) -> [k] -> [k]
399 -> TreeMap k x -> a -> a
401 go f p (k:n) (TreeMap t) a =
402 case Data.Map.lookup k t of
404 Just Node{node_value=v, node_descendants=d} ->
406 Strict.Nothing -> go f (k:p) n d a
407 Strict.Just x -> f (reverse $ path k p) x $ go f (k:p) n d a
411 -- | Return a 'Map' associating each 'Path'
412 -- leading to a non-'Strict.Nothing' 'node_value' in the given 'TreeMap',
413 -- with its value mapped by the given function.
414 flatten :: Ord k => (x -> y) -> TreeMap k x -> Map (Path k) y
415 flatten = flatten_with_Path . const
417 -- | Like 'flatten' but with also the current 'Path' given to the mapping function.
418 flatten_with_Path :: Ord k => (Path k -> x -> y) -> TreeMap k x -> Map (Path k) y
423 => [k] -> (Path k -> x -> y)
426 flat_map p f (TreeMap m) =
429 Data.Map.mapKeysMonotonic (reverse . flip path p) $
430 Data.Map.mapMaybeWithKey (\k Node{node_value} ->
432 Strict.Nothing -> Nothing
433 Strict.Just x -> Just $ f (reverse $ path k p) x) m
435 Data.Map.foldrWithKey
436 (\k -> (:) . flat_map (k:p) f . node_descendants)
441 -- | Return the given 'TreeMap'
442 -- keeping only its non-'Strict.Nothing' 'node_value's
443 -- passing the given predicate.
444 filter :: Ord k => (x -> Bool) -> TreeMap k x -> TreeMap k x
447 (\_p x -> if f x then Strict.Just x else Strict.Nothing)
449 -- | Like 'filter' but with also the current 'Path' given to the predicate.
450 filter_with_Path :: Ord k => (Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
453 (\p x -> if f p x then Strict.Just x else Strict.Nothing)
455 -- | Like 'filter_with_Path' but with also the current 'Node' given to the predicate.
456 filter_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Bool) -> TreeMap k x -> TreeMap k x
457 filter_with_Path_and_Node f =
458 map_Maybe_with_Path_and_Node
459 (\n p x -> if f n p x then Strict.Just x else Strict.Nothing)
461 -- | Return the given 'TreeMap'
462 -- mapping its non-'Strict.Nothing' 'node_value's
463 -- and keeping only the non-'Strict.Nothing' results.
464 map_Maybe :: Ord k => (x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
465 map_Maybe = map_Maybe_with_Path . const
467 -- | Like 'map_Maybe' but with also the current 'Path' given to the predicate.
468 map_Maybe_with_Path :: Ord k => (Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
469 map_Maybe_with_Path = map_Maybe_with_Path_and_Node . const
471 -- | Like 'map_Maybe_with_Path' but with also the current 'Node' given to the predicate.
472 map_Maybe_with_Path_and_Node :: Ord k => (Node k x -> Path k -> x -> Strict.Maybe y) -> TreeMap k x -> TreeMap k y
473 map_Maybe_with_Path_and_Node =
477 => [k] -> (Node k x -> Path k -> x -> Strict.Maybe y)
480 go p test (TreeMap m) =
482 Data.Map.mapMaybeWithKey
483 (\k node@Node{node_value=v, node_descendants=ns} ->
484 let node_descendants = go (k:p) test ns in
485 let node_size = size node_descendants in
488 let node_value = test node (reverse $ path k p) x in
490 Strict.Nothing | null node_descendants -> Nothing
491 Strict.Nothing -> Just Node{node_value, node_descendants, node_size=1 + node_size}
492 Strict.Just _ -> Just Node{node_value, node_descendants, node_size}
494 if null node_descendants
496 else Just Node{node_value=Strict.Nothing, node_descendants, node_size}