{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies
, FlexibleContexts, Rank2Types #-}
module Data.ListTrie.Base
( Trie(..)
, null, size, size', member, notMember, lookup, lookupWithDefault
, isSubmapOfBy, isProperSubmapOfBy
, empty, singleton
, insert, insert', insertWith, insertWith'
, delete, adjust, adjust', updateLookup, alter, alter'
, unionWith, unionWithKey, unionWith', unionWithKey'
, unionsWith, unionsWithKey, unionsWith', unionsWithKey'
, differenceWith, differenceWithKey
, intersectionWith, intersectionWithKey
, intersectionWith', intersectionWithKey'
, filterWithKey, partitionWithKey
, split, splitLookup
, mapKeysWith, mapInKeysWith, mapInKeysWith'
, foldrWithKey, foldrAscWithKey, foldrDescWithKey
, foldlWithKey, foldlAscWithKey, foldlDescWithKey
, foldlWithKey', foldlAscWithKey', foldlDescWithKey'
, toList, toAscList, toDescList
, fromList, fromListWith, fromListWith', fromListWithKey, fromListWithKey'
, findMin, findMax, deleteMin, deleteMax, minView, maxView
, findPredecessor, findSuccessor
, lookupPrefix, addPrefix, deletePrefix, deleteSuffixes
, splitPrefix, children, children1
, showTrieWith
) where
import Control.Applicative (Applicative(..), (<$>))
import Control.Arrow ((***), first)
import qualified Data.DList as DL
import Data.DList (DList)
import Data.Foldable (foldr, foldl')
import Data.List (partition)
import Data.Maybe (fromJust)
import Prelude hiding (lookup, filter, foldr, null)
import qualified Prelude
import qualified Data.ListTrie.Base.Map.Internal as Map
import Data.ListTrie.Base.Classes
( Boolable(..)
, Unwrappable(..)
, Unionable(..), Differentiable(..), Intersectable(..)
, Alt(..)
, fmap', (<$!>)
)
import Data.ListTrie.Base.Map (Map, OrdMap)
import Data.ListTrie.Util ((.:), both)
class (Map map k, Functor st, Unwrappable st)
=> Trie trie st map k | trie -> st where
mkTrie :: st a -> CMap trie map k a -> trie map k a
tParts :: trie map k a -> (st a, CMap trie map k a)
type CMap trie map k v = map k (trie map k v)
hasValue, noValue :: Boolable b => b -> Bool
hasValue = toBool
noValue = not . hasValue
tVal :: Trie trie st map k => trie map k a -> st a
tVal = fst . tParts
tMap :: Trie trie st map k => trie map k a -> CMap trie map k a
tMap = snd . tParts
mapVal :: Trie trie st map k => (forall x y. (x -> y) -> x -> y)
-> trie map k a
-> (st a -> st a)
-> trie map k a
mapVal ($$) tr f = (mkTrie $$ (f . tVal $ tr)) (tMap tr)
mapMap :: (Trie trie st map k1, Trie trie st map k2)
=> (forall x y. (x -> y) -> x -> y)
-> trie map k1 a
-> (CMap trie map k1 a -> CMap trie map k2 a)
-> trie map k2 a
mapMap ($$) tr f = (mkTrie $$ tVal tr) (f . tMap $ tr)
onVals :: Trie trie st map k => (forall x y. (x -> y) -> x -> y)
-> (st a -> st b -> st c)
-> trie map k a
-> trie map k b
-> st c
onVals ($$) f a b = f $$ tVal a $$ tVal b
onMaps :: Trie trie st map k => (forall x y. (x -> y) -> x -> y)
-> ( CMap trie map k a
-> CMap trie map k b
-> CMap trie map k c
)
-> trie map k a
-> trie map k b
-> CMap trie map k c
onMaps ($$) f a b = f $$ tMap a $$ tMap b
empty :: (Alt st a, Trie trie st map k) => trie map k a
empty = mkTrie altEmpty Map.empty
singleton :: (Alt st a, Trie trie st map k) => [k] -> a -> trie map k a
singleton xs v = addPrefix xs $ mkTrie (pure v) Map.empty
insert :: (Alt st a, Trie trie st map k)
=> [k] -> a -> trie map k a -> trie map k a
insert = insertWith const
insert' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> a -> trie map k a -> trie map k a
insert' = insertWith' const
insertWith :: (Alt st a, Trie trie st map k)
=> (a -> a -> a) -> [k] -> a -> trie map k a -> trie map k a
insertWith = genericInsertWith ($) (<$>)
insertWith' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (a -> a -> a) -> [k] -> a -> trie map k a -> trie map k a
insertWith' = (seq <*>) .: genericInsertWith ($!) (<$!>)
genericInsertWith :: (Alt st a, Trie trie st map k)
=> (forall x y. (x -> y) -> x -> y)
-> ((a -> a) -> st a -> st a)
-> (a -> a -> a) -> [k] -> a -> trie map k a -> trie map k a
genericInsertWith ($$) (<$$>) f = go
where
go [] new tr =
mapVal ($$) tr $ \old -> (f new <$$> old) <|> pure new
go (x:xs) val tr = mapMap ($$) tr $ \m ->
Map.insertWith (\_ old -> go xs val old) x (singleton xs val) m
delete :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> trie map k a -> trie map k a
delete = alter (const altEmpty)
adjust :: Trie trie st map k
=> (a -> a) -> [k] -> trie map k a -> trie map k a
adjust = genericAdjust ($) fmap
adjust' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (a -> a) -> [k] -> trie map k a -> trie map k a
adjust' = genericAdjust ($!) fmap'
genericAdjust :: Trie trie st map k
=> (forall x y. (x -> y) -> x -> y)
-> ((a -> a) -> st a -> st a)
-> (a -> a) -> [k] -> trie map k a -> trie map k a
genericAdjust ($$) (<$$>) f = go
where
go [] tr = mapVal ($$) tr (f <$$>)
go (x:xs) tr = mapMap ($$) tr (Map.adjust (go xs) x)
updateLookup :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (a -> st a) -> [k] -> trie map k a -> (st a, trie map k a)
updateLookup f = go
where
go [] tr =
let (v,m) = tParts tr
v' = if hasValue v then f (unwrap v) else v
in (v, mkTrie v' m)
go (x:xs) orig =
let m = tMap orig
in case Map.lookup x m of
Nothing -> (altEmpty, orig)
Just tr ->
let (ret, upd) = go xs tr
in ( ret
, mkTrie (tVal orig) $ if null upd
then Map.delete x m
else Map.adjust (const upd) x m
)
alter :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (st a -> st a) -> [k] -> trie map k a -> trie map k a
alter = genericAlter ($) (flip const)
alter' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (st a -> st a) -> [k] -> trie map k a -> trie map k a
alter' = genericAlter ($!) seq
genericAlter :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (forall x y. (x -> y) -> x -> y)
-> (st a -> trie map k a -> trie map k a)
-> (st a -> st a) -> [k] -> trie map k a -> trie map k a
genericAlter ($$) seeq f = go
where
go [] tr =
let (v,m) = tParts tr
v' = f v
in v' `seeq` mkTrie v' m
go (x:xs) tr = mapMap ($$) tr $ \m ->
Map.alter (\mold -> case mold of
Nothing ->
let v = f altEmpty
in if hasValue v
then Just (singleton xs (unwrap v))
else Nothing
Just old ->
let new = go xs old
in if null new then Nothing else Just new)
x m
null :: (Boolable (st a), Trie trie st map k) => trie map k a -> Bool
null tr = Map.null (tMap tr) && (noValue.tVal $ tr)
size :: (Boolable (st a), Trie trie st map k, Num n) => trie map k a -> n
size tr = foldr ((+) . size) (if hasValue (tVal tr) then 1 else 0) (tMap tr)
size' :: (Boolable (st a), Trie trie st map k, Num n) => trie map k a -> n
size' tr = foldl' (flip $ (+) . size')
(if hasValue (tVal tr) then 1 else 0)
(tMap tr)
member :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> trie map k a -> Bool
member = hasValue .: lookup
notMember :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> trie map k a -> Bool
notMember = not .: member
lookup :: (Alt st a, Trie trie st map k) => [k] -> trie map k a -> st a
lookup [] tr = tVal tr
lookup (x:xs) tr = maybe altEmpty (lookup xs) (Map.lookup x (tMap tr))
lookupWithDefault :: (Alt st a, Trie trie st map k)
=> a -> [k] -> trie map k a -> a
lookupWithDefault def k tr = unwrap $ lookup k tr <|> pure def
isSubmapOfBy :: (Boolable (st a), Boolable (st b), Trie trie st map k)
=> (a -> b -> Bool)
-> trie map k a
-> trie map k b
-> Bool
isSubmapOfBy f = go
where
go tr1 tr2 =
let (v1,m1) = tParts tr1
(v2,m2) = tParts tr2
hv1 = hasValue v1
hv2 = hasValue v2
in and [ not (hv1 && not hv2)
, (not hv1 && not hv2) || f (unwrap v1) (unwrap v2)
, Map.isSubmapOfBy go m1 m2
]
isProperSubmapOfBy :: (Boolable (st a), Boolable (st b), Trie trie st map k)
=> (a -> b -> Bool)
-> trie map k a
-> trie map k b
-> Bool
isProperSubmapOfBy f = go False
where
go proper tr1 tr2 =
let (v1,m1) = tParts tr1
(v2,m2) = tParts tr2
hv1 = hasValue v1
hv2 = hasValue v2
proper' = or [ proper
, noValue v1 && hasValue v2
, not (Map.null $ Map.difference m2 m1)
]
in and [ not (hv1 && not hv2)
, (not hv1 && not hv2) || f (unwrap v1) (unwrap v2)
, if Map.null m1
then proper'
else Map.isSubmapOfBy (go proper') m1 m2
]
unionWith :: (Unionable st a, Trie trie st map k)
=> (a -> a -> a) -> trie map k a -> trie map k a -> trie map k a
unionWith f = genericUnionWith ($) (unionVals f) (flip const)
unionWith' :: (Unionable st a, Trie trie st map k)
=> (a -> a -> a) -> trie map k a -> trie map k a -> trie map k a
unionWith' f = genericUnionWith ($!) (unionVals' f) seq
genericUnionWith :: Trie trie st map k
=> (forall x y. (x -> y) -> x -> y)
-> (st a -> st a -> st a)
-> (st a -> trie map k a -> trie map k a)
-> trie map k a
-> trie map k a
-> trie map k a
genericUnionWith ($$) valUnion seeq = go
where
go tr1 tr2 =
let v = onVals ($$) valUnion tr1 tr2
in v `seeq` (mkTrie v $ onMaps ($$) (Map.unionWith go) tr1 tr2)
unionWithKey :: (Unionable st a, Trie trie st map k) => ([k] -> a -> a -> a)
-> trie map k a
-> trie map k a
-> trie map k a
unionWithKey = genericUnionWithKey ($) unionVals (flip const)
unionWithKey' :: (Unionable st a, Trie trie st map k) => ([k] -> a -> a -> a)
-> trie map k a
-> trie map k a
-> trie map k a
unionWithKey' = genericUnionWithKey ($!) unionVals' seq
genericUnionWithKey :: Trie trie st map k
=> (forall x y. (x -> y) -> x -> y)
-> ((a -> a -> a) -> st a -> st a -> st a)
-> (st a -> trie map k a -> trie map k a)
-> ([k] -> a -> a -> a)
-> trie map k a
-> trie map k a
-> trie map k a
genericUnionWithKey ($$) valUnion seeq f = go DL.empty
where
go k tr1 tr2 =
let v = onVals ($$) (valUnion (f $ DL.toList k)) tr1 tr2
in v `seeq` (mkTrie v $
onMaps ($$) (Map.unionWithKey $ go . (k `DL.snoc`))
tr1 tr2)
unionsWith :: (Alt st a, Unionable st a, Trie trie st map k)
=> (a -> a -> a) -> [trie map k a] -> trie map k a
unionsWith f = foldl' (unionWith f) empty
unionsWith' :: (Alt st a, Unionable st a, Trie trie st map k)
=> (a -> a -> a) -> [trie map k a] -> trie map k a
unionsWith' f = foldl' (unionWith' f) empty
unionsWithKey :: (Alt st a, Unionable st a, Trie trie st map k)
=> ([k] -> a -> a -> a) -> [trie map k a] -> trie map k a
unionsWithKey j = foldl' (unionWithKey j) empty
unionsWithKey' :: (Alt st a, Unionable st a, Trie trie st map k)
=> ([k] -> a -> a -> a) -> [trie map k a] -> trie map k a
unionsWithKey' j = foldl' (unionWithKey' j) empty
differenceWith :: (Boolable (st a), Differentiable st a b, Trie trie st map k)
=> (a -> b -> Maybe a)
-> trie map k a
-> trie map k b
-> trie map k a
differenceWith f = go
where
go tr1 tr2 =
let v = onVals ($!) (differenceVals f) tr1 tr2
in v `seq` mkTrie v $ onMaps ($!) (Map.differenceWith g) tr1 tr2
g t1 t2 = let t' = go t1 t2
in if null t' then Nothing else Just t'
differenceWithKey :: ( Boolable (st a), Differentiable st a b
, Trie trie st map k
)
=> ([k] -> a -> b -> Maybe a)
-> trie map k a
-> trie map k b
-> trie map k a
differenceWithKey f = go DL.empty
where
go k tr1 tr2 =
let v = onVals ($!) (differenceVals (f $ DL.toList k)) tr1 tr2
in v `seq` mkTrie v $
onMaps ($!) (Map.differenceWithKey (g k)) tr1 tr2
g k x t1 t2 = let t' = go (k `DL.snoc` x) t1 t2
in if null t' then Nothing else Just t'
intersectionWith :: ( Boolable (st c), Intersectable st a b c
, Trie trie st map k
)
=> (a -> b -> c)
-> trie map k a
-> trie map k b
-> trie map k c
intersectionWith f = genericIntersectionWith ($) (intersectionVals f) (flip const)
intersectionWith' :: ( Boolable (st c), Intersectable st a b c
, Trie trie st map k
)
=> (a -> b -> c)
-> trie map k a
-> trie map k b
-> trie map k c
intersectionWith' f = genericIntersectionWith ($!) (intersectionVals' f) seq
genericIntersectionWith :: (Boolable (st c), Trie trie st map k)
=> (forall x y. (x -> y) -> x -> y)
-> (st a -> st b -> st c)
-> (st c -> trie map k c -> trie map k c)
-> trie map k a
-> trie map k b
-> trie map k c
genericIntersectionWith ($$) valIntersection seeq = go
where
go tr1 tr2 =
tr seeq
(onVals ($$) valIntersection tr1 tr2)
(onMaps ($$) (Map.filter (not.null) .: Map.intersectionWith go)
tr1 tr2)
tr seeq' v m =
v `seeq'` (mkTrie v $
case Map.singletonView m of
Just (_, child) | null child -> tMap child
_ -> m)
intersectionWithKey :: ( Boolable (st c), Intersectable st a b c
, Trie trie st map k
)
=> ([k] -> a -> b -> c)
-> trie map k a
-> trie map k b
-> trie map k c
intersectionWithKey =
genericIntersectionWithKey ($) intersectionVals (flip const)
intersectionWithKey' :: ( Boolable (st c), Intersectable st a b c
, Trie trie st map k
)
=> ([k] -> a -> b -> c)
-> trie map k a
-> trie map k b
-> trie map k c
intersectionWithKey' = genericIntersectionWithKey ($!) intersectionVals' seq
genericIntersectionWithKey :: (Boolable (st c), Trie trie st map k)
=> (forall x y. (x -> y) -> x -> y)
-> ((a -> b -> c) -> st a -> st b -> st c)
-> (st c -> trie map k c -> trie map k c)
-> ([k] -> a -> b -> c)
-> trie map k a
-> trie map k b
-> trie map k c
genericIntersectionWithKey ($$) valIntersection seeq f = go DL.empty
where
go k tr1 tr2 =
tr
(onVals ($$) (valIntersection (f $ DL.toList k)) tr1 tr2)
(onMaps ($$) (Map.filter (not.null) .:
Map.intersectionWithKey (go . (k `DL.snoc`)))
tr1 tr2)
tr v m =
v `seeq` (mkTrie v $
case Map.singletonView m of
Just (_, child) | null child -> tMap child
_ -> m)
filterWithKey :: (Alt st a, Boolable (st a), Trie trie st map k)
=> ([k] -> a -> Bool) -> trie map k a -> trie map k a
filterWithKey p = fromList . Prelude.filter (uncurry p) . toList
partitionWithKey :: (Alt st a, Boolable (st a), Trie trie st map k)
=> ([k] -> a -> Bool)
-> trie map k a
-> (trie map k a, trie map k a)
partitionWithKey p = both fromList . partition (uncurry p) . toList
mapKeysWith :: (Boolable (st a), Trie trie st map k1, Trie trie st map k2)
=> ([([k2],a)] -> trie map k2 a)
-> ([k1] -> [k2])
-> trie map k1 a
-> trie map k2 a
mapKeysWith fromlist f = fromlist . map (first f) . toList
mapInKeysWith :: (Unionable st a, Trie trie st map k1, Trie trie st map k2)
=> (a -> a -> a)
-> (k1 -> k2)
-> trie map k1 a
-> trie map k2 a
mapInKeysWith = genericMapInKeysWith ($) unionWith
mapInKeysWith' :: (Unionable st a, Trie trie st map k1, Trie trie st map k2)
=> (a -> a -> a)
-> (k1 -> k2)
-> trie map k1 a
-> trie map k2 a
mapInKeysWith' = genericMapInKeysWith ($!) unionWith'
genericMapInKeysWith :: ( Unionable st a
, Trie trie st map k1, Trie trie st map k2
)
=> (forall x y. (x -> y) -> x -> y)
-> (f -> trie map k2 a -> trie map k2 a -> trie map k2 a)
-> f
-> (k1 -> k2)
-> trie map k1 a
-> trie map k2 a
genericMapInKeysWith ($$) unionW j f = go
where
go tr = mapMap ($$) tr $
Map.fromListKVWith (unionW j) . map (f *** go) . Map.toListKV
foldrWithKey :: (Boolable (st a), Trie trie st map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldrWithKey f x = foldr (uncurry f) x . toList
foldrAscWithKey :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldrAscWithKey f x = foldr (uncurry f) x . toAscList
foldrDescWithKey :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldrDescWithKey f x = foldr (uncurry f) x . toDescList
foldlWithKey :: (Boolable (st a), Trie trie st map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlWithKey f x = foldl (flip $ uncurry f) x . toList
foldlAscWithKey :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlAscWithKey f x = foldl (flip $ uncurry f) x . toAscList
foldlDescWithKey :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlDescWithKey f x = foldl (flip $ uncurry f) x . toDescList
foldlWithKey' :: (Boolable (st a), Trie trie st map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlWithKey' f x = foldl' (flip $ uncurry f) x . toList
foldlAscWithKey' :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlAscWithKey' f x = foldl' (flip $ uncurry f) x . toAscList
foldlDescWithKey' :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> ([k] -> a -> b -> b) -> b -> trie map k a -> b
foldlDescWithKey' f x = foldl' (flip $ uncurry f) x . toDescList
toList :: (Boolable (st a), Trie trie st map k) => trie map k a -> [([k],a)]
toList = genericToList Map.toListKV DL.cons
toAscList :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> [([k],a)]
toAscList = genericToList Map.toAscList DL.cons
toDescList :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> [([k],a)]
toDescList = genericToList (reverse . Map.toAscList) (flip DL.snoc)
genericToList :: (Boolable (st a), Trie trie st map k)
=> (CMap trie map k a -> [(k, trie map k a)])
-> (([k],a) -> DList ([k],a) -> DList ([k],a))
-> trie map k a
-> [([k],a)]
genericToList tolist add = DL.toList . go DL.empty
where
go xs tr =
let (v,m) = tParts tr
xs' =
DL.concat .
map (\(x,t) -> go (xs `DL.snoc` x) t) .
tolist $ m
in if hasValue v
then add (DL.toList xs, unwrap v) xs'
else xs'
fromList :: (Alt st a, Trie trie st map k) => [([k],a)] -> trie map k a
fromList = fromListWith const
fromListWith :: (Alt st a, Trie trie st map k)
=> (a -> a -> a) -> [([k],a)] -> trie map k a
fromListWith f = foldl' (flip . uncurry $ insertWith f) empty
fromListWith' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (a -> a -> a) -> [([k],a)] -> trie map k a
fromListWith' f = foldl' (flip . uncurry $ insertWith' f) empty
fromListWithKey :: (Alt st a, Trie trie st map k)
=> ([k] -> a -> a -> a) -> [([k],a)] -> trie map k a
fromListWithKey f = foldl' (\tr (k,v) -> insertWith (f k) k v tr) empty
fromListWithKey' :: (Alt st a, Boolable (st a), Trie trie st map k)
=> ([k] -> a -> a -> a) -> [([k],a)] -> trie map k a
fromListWithKey' f = foldl' (\tr (k,v) -> insertWith' (f k) k v tr) empty
minView :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> (Maybe ([k], a), trie map k a)
minView = minMaxView (hasValue . tVal) (fst . Map.minViewWithKey)
maxView :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> (Maybe ([k], a), trie map k a)
maxView = minMaxView (Map.null . tMap) (fst . Map.maxViewWithKey)
minMaxView :: (Alt st a, Boolable (st a), Trie trie st map k)
=> (trie map k a -> Bool)
-> (CMap trie map k a -> Maybe (k, trie map k a))
-> trie map k a
-> (Maybe ([k], a), trie map k a)
minMaxView _ _ tr_ | null tr_ = (Nothing, tr_)
minMaxView isWanted mapView tr_ = first Just (go tr_)
where
go tr =
let (v,m) = tParts tr
in if isWanted tr
then (([], unwrap v), mkTrie altEmpty m)
else let (k, tr') = fromJust (mapView m)
(minMax, tr'') = go tr'
in ( first (k:) minMax
, mkTrie v $ if null tr''
then Map.delete k m
else Map.adjust (const tr'') k m
)
findMin :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> Maybe ([k], a)
findMin = findMinMax (hasValue . tVal) (fst . Map.minViewWithKey)
findMax :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> Maybe ([k], a)
findMax = findMinMax (Map.null . tMap) (fst . Map.maxViewWithKey)
findMinMax :: (Boolable (st a), Trie trie st map k)
=> (trie map k a -> Bool)
-> (CMap trie map k a -> Maybe (k, trie map k a))
-> trie map k a
-> Maybe ([k], a)
findMinMax _ _ tr_ | null tr_ = Nothing
findMinMax isWanted mapView tr_ = Just (go DL.empty tr_)
where
go xs tr =
if isWanted tr
then (DL.toList xs, unwrap (tVal tr))
else let (k, tr') = fromJust . mapView . tMap $ tr
in go (xs `DL.snoc` k) tr'
deleteMin :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> trie map k a
deleteMin = snd . minView
deleteMax :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> trie map k a -> trie map k a
deleteMax = snd . maxView
split :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> [k] -> trie map k a -> (trie map k a, trie map k a)
split xs tr = let (l,_,g) = splitLookup xs tr in (l,g)
splitLookup :: (Alt st a, Boolable (st a), Trie trie st map k, OrdMap map k)
=> [k]
-> trie map k a
-> (trie map k a, st a, trie map k a)
splitLookup [] tr = (empty, tVal tr, mkTrie altEmpty (tMap tr))
splitLookup (x:xs) tr =
let (v,m) = tParts tr
(ml, subTr, mg) = Map.splitLookup x m
in case subTr of
Nothing -> (mkTrie v ml, altEmpty, mkTrie altEmpty mg)
Just tr' ->
let (tl, v', tg) = splitLookup xs tr'
ml' = if null tl then ml else Map.insert x tl ml
mg' = if null tg then mg else Map.insert x tg mg
in (mkTrie v ml', v', mkTrie altEmpty mg')
findPredecessor :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> [k] -> trie map k a -> Maybe ([k], a)
findPredecessor _ tr | null tr = Nothing
findPredecessor xs_ tr_ = go xs_ tr_
where
go [] _ = Nothing
go (x:xs) tr =
let (v,m) = tParts tr
predecessor = Map.findPredecessor x m
in fmap (first (x:)) (Map.lookup x m >>= go xs)
<|>
case predecessor of
Nothing ->
if hasValue v
then Just ([], unwrap v)
else Nothing
Just (best,btr) -> fmap (first (best:)) (findMax btr)
findSuccessor :: forall trie map st k a .
(Boolable (st a), Trie trie st map k, OrdMap map k)
=> [k] -> trie map k a -> Maybe ([k], a)
findSuccessor _ tr | null tr = Nothing
findSuccessor xs_ tr_ = go xs_ tr_
where
go :: (Boolable (st a), Trie trie st map k, OrdMap map k)
=> [k] -> trie map k a -> Maybe ([k], a)
go [] tr = do (k,t) <- fst . Map.minViewWithKey . tMap $ tr
fmap (first (k:)) (findMin t)
go (x:xs) tr =
let m = tMap tr
successor = Map.findSuccessor x m
in fmap (first (x:)) (Map.lookup x m >>= go xs)
<|>
(successor >>= \(best,btr) -> fmap (first (best:)) (findMin btr))
lookupPrefix :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> trie map k a -> trie map k a
lookupPrefix [] tr = tr
lookupPrefix (x:xs) tr =
case Map.lookup x (tMap tr) of
Nothing -> empty
Just tr' -> let tr'' = lookupPrefix xs tr'
in if null tr''
then tr''
else mkTrie altEmpty (Map.singleton x tr'')
addPrefix :: (Alt st a, Trie trie st map k)
=> [k] -> trie map k a -> trie map k a
addPrefix [] = id
addPrefix (x:xs) = mkTrie altEmpty . Map.singleton x . addPrefix xs
deletePrefix :: (Alt st a, Trie trie st map k)
=> [k] -> trie map k a -> trie map k a
deletePrefix [] tr = tr
deletePrefix (x:xs) tr =
case Map.lookup x (tMap tr) of
Nothing -> empty
Just tr' -> deletePrefix xs tr'
deleteSuffixes :: (Alt st a, Boolable (st a), Trie trie st map k)
=> [k] -> trie map k a -> trie map k a
deleteSuffixes [] _ = empty
deleteSuffixes (x:xs) tr =
let (v,m) = tParts tr
in case Map.lookup x m of
Nothing -> tr
Just tr' -> let tr'' = deleteSuffixes xs tr'
in if null tr''
then mkTrie v (Map.delete x m)
else mkTrie v (Map.insert x tr'' m)
splitPrefix :: forall trie map st k a .
(Alt st a, Trie trie st map k)
=> trie map k a -> ([k], st a, trie map k a)
splitPrefix = go DL.empty
where
go :: (Alt st a, Trie trie st map k)
=> DL.DList k -> trie map k a -> ([k], st a, trie map k a)
go xs tr =
case Map.singletonView (tMap tr) of
Just (x,tr') -> go (xs `DL.snoc` x) tr'
Nothing -> let (v,m) = tParts tr
in (DL.toList xs, v, mkTrie altEmpty m)
children :: (Boolable (st a), Trie trie st map k)
=> trie map k a -> CMap trie map k a
children tr = let (v,m) = tParts tr
in if hasValue v
then m
else case Map.singletonView m of
Just (_, tr') -> children tr'
Nothing -> m
children1 :: (Alt st a, Trie trie st map k)
=> trie map k a -> CMap trie map k a
children1 = tMap
showTrieWith :: (Show k, Trie trie st map k)
=> (st a -> ShowS) -> trie map k a -> ShowS
showTrieWith = go 0
where
go indent f tr =
let (v,m) = tParts tr
sv = f v
lv = length (sv [])
in sv . showChar ' '
. (foldr (.) id . zipWith (flip ($)) (False : repeat True) $
map (\(k,t) -> \b -> let sk = shows k
lk = length (sk [])
i = indent + lv + 1
in (if b
then showChar '\n'
. showString (replicate i ' ')
else id)
. showString "-> "
. sk . showChar ' '
. go (i + lk + 4) f t)
(Map.toListKV m))