module Data.Rewriting.FirstOrder where
import Control.Monad.Reader
import Control.Monad.Writer
import Data.Foldable (Foldable)
import Data.Function (on)
import Data.List (groupBy)
import Data.Traversable (Traversable)
import Data.Comp
import Data.Comp.Ops
import Data.Rewriting.Rules
matchM :: (Functor f, Foldable f, EqF f) => LHS f a -> Term f -> WriterT (Subst f) Maybe ()
matchM (LHS lhs) t = go lhs t
where
go (Term (Inl WildCard)) _ = return ()
go (Term (Inr (Inl (Meta (MVar (MetaId v)))))) t = tell [(v,t)]
go (Term (Inr (Inr f))) (Term g)
| Just subs <- eqMod f g = mapM_ (uncurry go) subs
go _ _ = fail "No match"
solveTerm :: EqF f => [Term f] -> Maybe (Term f)
solveTerm (t:ts) = guard (all (==t) ts) >> return t
solveTerm _ = Nothing
solveSubst :: EqF f => [(Name, Term f)] -> Maybe (Subst f)
solveSubst s = sequence [fmap (v,) $ solveTerm ts | g <- gs, let (v:_,ts) = unzip g]
where
gs = groupBy ((==) `on` fst) s
match :: (Functor f, Foldable f, EqF f) => LHS f a -> Term f -> Maybe (Subst f)
match lhs = solveSubst <=< execWriterT . matchM lhs
substitute :: Traversable f => Subst f -> RHS f a -> Maybe (Term f)
substitute subst = cataM go . unRHS
where
go (Inl (Meta (MVar (MetaId v)))) = lookup v subst
go (Inr f) = return (Term f)
rewrite :: (Traversable f, EqF f) => Rule (LHS f) (RHS f) -> Term f -> Maybe (Term f)
rewrite (Rule lhs rhs) t = do
subst <- match lhs t
substitute subst rhs
applyFirst :: (Traversable f, EqF f) => [Rule (LHS f) (RHS f)] -> Term f -> Term f
applyFirst rs t = case [t' | r <- rs, Just t' <- [rewrite r t]] of
t':_ -> t'
_ -> t
bottomUp :: (Traversable f, EqF f) => [Rule (LHS f) (RHS f)] -> Term f -> Term f
bottomUp rs = applyFirst rs . Term . fmap (bottomUp rs) . unTerm
topDown :: (Traversable f, EqF f) => [Rule (LHS f) (RHS f)] -> Term f -> Term f
topDown rs = Term . fmap (topDown rs) . unTerm . applyFirst rs