-- | -- -- Module: Control.Egison.Matcher.Collection -- Description: Matchers for collection data types -- Stability: experimental module Control.Egison.Matcher.Collection ( CollectionPattern(..) , List(..) , Multiset(..) , Set(..) ) where import Data.List ( tails ) import Control.Monad ( MonadPlus(..) ) import Control.Monad.Search import Control.Egison.Match import Control.Egison.Matcher import Control.Egison.Matcher.Pair import Control.Egison.QQ -- | Class for collection pattern constructors. class CollectionPattern m t where -- | Matcher for the elements. type ElemM m -- | Type of the target elements. type ElemT t -- | Pattern that matches with empty collections. -- @[]@ is desugared into 'nil' by the quasi-quoter. nil :: Pattern () m t () nilM :: m -> t -> () default nilM :: m -> t -> () {-# INLINE nilM #-} nilM _ _ = () -- | Pattern that destructs collections into its head and tail. -- @:@ is desugared into 'cons' by the quasi-quoter. cons :: Pattern (PP (ElemT t), PP t) m t (ElemT t, t) consM :: m -> t -> (ElemM m, m) -- | Pattern that destructs collections into its initial prefix and remaining suffix. -- @++@ is desugared into 'join' by the quasi-quoter. join :: Pattern (PP t, PP t) m t (t, t) joinM :: m -> t -> (m, m) default joinM :: m -> t -> (m, m) {-# INLINE joinM #-} joinM m _ = (m, m) elm :: Pattern (PP (ElemT t)) m t (ElemT t) elmM :: m -> t -> ElemM m joinCons :: Pattern (PP t, PP (ElemT t), PP t) m t (t, ElemT t, t) joinConsM :: m -> t -> (m, ElemM m, m) -- | 'List' matcher is a matcher for collections that matches as if they're normal lists. newtype List m = List m instance Matcher m t => Matcher (List m) [t] instance Matcher m t => CollectionPattern (List m) [t] where {-# SPECIALIZE instance Matcher m t => CollectionPattern (List m) [t] #-} type ElemM (List m) = m type ElemT [t] = t {-# INLINE nil #-} nil _ _ [] = pure () nil _ _ _ = mzero {-# INLINE cons #-} cons _ _ [] = mzero cons _ (List _) (x : xs) = pure (x, xs) {-# INLINE consM #-} consM (List m) _ = (m, List m) {-# INLINABLE join #-} join (WC, _) _ xs = map (\ts -> (undefined, ts)) (tails xs) join _ _ [] = pure ([], []) join ps m (x : xs) = pure ([], x : xs) `mplus` do (ys, zs) <- join ps m xs pure (x : ys, zs) {-# INLINE elm #-} elm _ (List _) xs = xs {-# INLINE elmM #-} elmM (List m) _ = m {-# INLINE joinCons #-} joinCons (WC, _, WC) (List _) tgt = [ (undefined, x, undefined) | x <- tgt ] joinCons (WC, _, _) (List _) tgt = [ (undefined, x, rs) | (x:rs) <- tails tgt ] joinCons (_, _, _) (List _) tgt = f [] tgt where f _ [] = [] f rhs (x : ts) = (reverse rhs, x, ts) : f (x : rhs) ts {-# INLINE joinConsM #-} joinConsM (List m) _ = (List m, m, List m) instance (Eq a, Matcher m a, ValuePattern m a) => ValuePattern (List m) [a] where value e () (List m) v = if eqAs (List m) (List m) e v then pure () else mzero newtype Multiset m = Multiset m instance Matcher m t => Matcher (Multiset m) [t] instance Matcher m t => CollectionPattern (Multiset m) [t] where {-# SPECIALIZE instance Matcher m t => CollectionPattern (Multiset m) [t] #-} type ElemM (Multiset m) = m type ElemT [t] = t {-# INLINE nil #-} nil _ _ [] = pure () nil _ _ _ = mzero {-# INLINE cons #-} cons (_, WC) (Multiset _) xs = map (\x -> (x, undefined)) xs cons _ (Multiset _) xs = matchAll dfs xs (List Something) [[mc| $hs ++ $x : $ts -> (x, hs ++ ts) |]] {-# INLINE consM #-} consM (Multiset m) _ = (m, Multiset m) {-# INLINABLE join #-} join = undefined elm = undefined elmM = undefined joinCons = undefined joinConsM = undefined instance (Eq a, Matcher m a, ValuePattern m a) => ValuePattern (Multiset m) [a] where value e () (Multiset m) v = if eqAs (List m) (Multiset m) e v then pure () else mzero newtype Set m = Set m instance Matcher m t => Matcher (Set m) [t] instance Matcher m t => CollectionPattern (Set m) [t] where {-# SPECIALIZE instance Matcher m t => CollectionPattern (Set m) [t] #-} type ElemM (Set m) = m type ElemT [t] = t {-# INLINE nil #-} nil _ _ [] = pure () nil _ _ _ = mzero {-# INLINE cons #-} cons (_, WC) (Set _) xs = map (\x -> (x, undefined)) xs cons _ (Set _) xs = map (\x -> (x, xs)) xs {-# INLINE consM #-} consM (Set m) _ = (m, Set m) {-# INLINABLE join #-} join = undefined elm = undefined elmM = undefined joinCons = undefined joinConsM = undefined instance (Eq a, Matcher m a, ValuePattern m a) => ValuePattern (Set m) [a] where value e () (Set m) v = if eqAs (List m) (Set m) e v then pure () else mzero eqAs :: (Matcher m1 t1, Matcher m2 t2, ValuePattern (ElemM m2) (ElemT t2), ElemT t1 ~ ElemT t2, CollectionPattern m1 t1, CollectionPattern m2 t2) => m1 -> m2 -> t1 -> t2 -> Bool eqAs m1 m2 xs ys = match dfs (xs, ys) (Pair m1 m2) [ [mc| ([], []) -> True |] , [mc| ($x : $xs, #x : $ys) -> eqAs m1 m2 xs ys |] , [mc| _ -> False |] ]