module Data.TrieMap.MultiRec.UnionMap where
import Data.TrieMap.MultiRec.Class
import Data.TrieMap.MultiRec.Eq
import Data.TrieMap.Applicative
import Data.TrieMap.TrieKey
import Control.Applicative
import Control.Arrow
import Control.Monad
import Data.Maybe
import Data.Foldable
import Generics.MultiRec
import Prelude hiding (foldr)
data UnionMap (phi :: * -> *) m1 m2 (r :: * -> *) (a :: * -> *) ix = m1 r a ix :&: m2 r a ix
type instance HTrieMapT phi (f :+: g) = UnionMap phi (HTrieMapT phi f) (HTrieMapT phi g)
type instance HTrieMap phi ((f :+: g) r) = HTrieMapT phi (f :+: g) r
instance (HTrieKeyT phi f m1, HTrieKeyT phi g m2) => HTrieKeyT phi (f :+: g) (UnionMap phi m1 m2) where
emptyT = liftM2 (:&:) emptyT emptyT
nullT pf (m1 :&: m2) = nullT pf m1 && nullT pf m2
sizeT s (m1 :&: m2) = sizeT s m1 + sizeT s m2
lookupT pf k (m1 :&: m2)
| L k <- k = lookupT pf k m1
| R k <- k = lookupT pf k m2
lookupIxT pf s k (m1 :&: m2)
| L k <- k = lookupIxT pf s k m1
| R k <- k = first (sizeT s m1 +) <$> lookupIxT pf s k m2
assocAtT pf s i (m1 :&: m2)
| i < s1, (i', k, a) <- assocAtT pf s i m1
= (i', L k, a)
| (i', k, a) <- assocAtT pf s (i s1) m2
= (i' + s1, R k, a)
where s1 = sizeT s m1
updateAtT pf s f i (m1 :&: m2)
| i < s1 = updateAtT pf s (\ i' -> f i' . L) i m1 :&: m2
| otherwise = m1 :&: updateAtT pf s (\ i' -> f (s1 + i') . R) (i s1) m2
where s1 = sizeT s m1
alterT pf s f k (m1 :&: m2)
| L k <- k = alterT pf s f k m1 :&: m2
| R k <- k = m1 :&: alterT pf s f k m2
traverseWithKeyT pf s f (m1 :&: m2)
= (:&:) <$> traverseWithKeyT pf s (f . L) m1 <*> traverseWithKeyT pf s (f . R) m2
foldWithKeyT pf f (m1 :&: m2)
= foldWithKeyT pf (f . L) m1 . foldWithKeyT pf (f . R) m2
foldlWithKeyT pf f (m1 :&: m2)
= foldlWithKeyT pf (f . R) m2 . foldlWithKeyT pf (f . L) m1
mapEitherT pf s1 s2 f (m1 :&: m2) = case (mapEitherT pf s1 s2 (f . L) m1, mapEitherT pf s1 s2 (f . R) m2) of
((m1L, m1R), (m2L, m2R)) -> (m1L :&: m2L, m1R :&: m2R)
splitLookupT pf s f k0 (m1 :&: m2)
| L k <- k0, (m1L, x, m1R) <- splitLookupT pf s f k m1
= (m1L :&: emptyT pf, x, m1R :&: m2)
| R k <- k0, (m2L, x, m2R) <- splitLookupT pf s f k m2
= (m1 :&: m2L, x, emptyT pf :&: m2R)
unionT pf s f (m11 :&: m12) (m21 :&: m22)
= unionT pf s (f . L) m11 m21 :&: unionT pf s (f . R) m12 m22
isectT pf s f (m11 :&: m12) (m21 :&: m22)
= isectT pf s (f . L) m11 m21 :&: isectT pf s (f . R) m12 m22
diffT pf s f (m11 :&: m12) (m21 :&: m22)
= diffT pf s (f . L) m11 m21 :&: diffT pf s (f . R) m12 m22
extractMinT pf s (m1 :&: m2) = (do
((k, v), m1') <- extractMinT pf s m1
return ((L k, v), m1' :&: m2)) `mplus`
(do ((k, v), m2') <- extractMinT pf s m2
return ((R k, v), m1 :&: m2'))
extractMaxT pf s (m1 :&: m2) = (do
((k, v), m1') <- extractMaxT pf s m1
return ((L k, v), m1' :&: m2)) `mplus`
(do ((k, v), m2') <- extractMaxT pf s m2
return ((R k, v), m1 :&: m2'))
alterMinT pf s f (m1 :&: m2)
| nullT pf m1 = m1 :&: alterMinT pf s (f . R) m2
| otherwise = alterMinT pf s (f . L) m1 :&: m2
alterMaxT pf s f (m1 :&: m2)
| nullT pf m2 = alterMaxT pf s (f . L) m1 :&: m2
| otherwise = m1 :&: alterMaxT pf s (f . R) m2
isSubmapT pf (<=) (m11 :&: m12) (m21 :&: m22)
= isSubmapT pf (<=) m11 m21 && isSubmapT pf (<=) m12 m22
fromListT pf s f xs = case breakEither xs of
(ys, zs) -> fromListT pf s (f . L) ys :&: fromListT pf s (f . R) zs
fromAscListT pf s f xs = case breakEither xs of
(ys, zs) -> fromAscListT pf s (f . L) ys :&: fromAscListT pf s (f . R) zs
fromDistAscListT pf s xs = case breakEither xs of
(ys, zs) -> fromDistAscListT pf s ys :&: fromDistAscListT pf s zs
breakEither :: [((f :+: g) r ix, a)] -> ([(f r ix, a)], [(g r ix, a)])
breakEither = foldr breakEither' ([], []) where
breakEither' (L k, a) (xs, ys) = ((k, a):xs, ys)
breakEither' (R k, a) (xs, ys) = (xs, (k, a):ys)
instance (HTrieKeyT phi f m1, m1 ~ HTrieMapT phi f, HTrieKeyT phi g m2, m2 ~ HTrieMapT phi g,
HTrieKey phi r (HTrieMap phi r)) => HTrieKey phi ((f :+: g) r) (UnionMap phi m1 m2 r) where
emptyH = emptyT
nullH = nullT
sizeH = sizeT
lookupH = lookupT
lookupIxH = lookupIxT
assocAtH = assocAtT
updateAtH = updateAtT
alterH = alterT
traverseWithKeyH = traverseWithKeyT
foldWithKeyH = foldWithKeyT
foldlWithKeyH = foldlWithKeyT
mapEitherH = mapEitherT
splitLookupH = splitLookupT
unionH = unionT
isectH = isectT
diffH = diffT
alterMinH = alterMinT
alterMaxH = alterMaxT
extractMinH = extractMinT
extractMaxH = extractMaxT
isSubmapH = isSubmapT
fromListH = fromListT
fromAscListH = fromAscListT
fromDistAscListH = fromDistAscListT