{-# LANGUAGE FlexibleContexts #-}
module Data.Rewriting.Substitution.Unify (
unify,
unifyRef,
) where
import Data.Rewriting.Substitution.Type
import Data.Rewriting.Substitution.Ops (apply)
import qualified Data.Rewriting.Term.Ops as Term
import qualified Data.Rewriting.Term.Type as Term
import Data.Rewriting.Term.Type (Term (..))
import qualified Data.Map as M
import qualified Control.Monad.Union as UM
import qualified Data.Union as U
import Control.Monad.State
import Control.Monad.ST
import Control.Applicative
import Control.Arrow
import Data.Array.ST
import Data.Array
import Data.Maybe
import Data.Word
type UnifyM f v a = StateT (M.Map v U.Node) (UM.UnionM (Annot f v)) a
data Annot f v = VarA v | FunA f [U.Node] | FunP f [Term f v]
funari :: Annot f v -> (f, Int)
funari (FunA f ns) = (f, length ns)
funari (FunP f ts) = (f, length ts)
solve :: (Eq f, Ord v) => [(U.Node, U.Node)] -> UnifyM f v Bool
solve [] = return True
solve ((t, u) : xs) = do
(t, t') <- UM.lookup t
(u, u') <- UM.lookup u
if t == u then solve xs else case (t', u') of
(VarA _, _) -> do
UM.merge (\_ _ -> (u', ())) t u
solve xs
(_, VarA _) -> do
UM.merge (\_ _ -> (t', ())) t u
solve xs
_ | funari t' == funari u' ->
expand t t' >>= \(FunA _ ts) ->
expand u u' >>= \(FunA _ us) ->
UM.merge (\t _ -> (t, ())) t u >>
solve (zip ts us ++ xs)
_ -> do
return False
expand :: (Ord v) => U.Node -> Annot f v -> UnifyM f v (Annot f v)
expand n (FunP f ts) = do
ann <- FunA f <$> mapM mkNode ts
UM.annotate n ann
return ann
expand n ann = return ann
mkNode :: (Ord v) => Term f v -> UnifyM f v U.Node
mkNode (Var v) = do
n <- gets (M.lookup v)
case n of
Just n -> return n
Nothing -> do
n <- UM.new (VarA v)
modify (M.insert v n)
return n
mkNode (Fun f ts) = UM.new (FunP f ts)
unify :: (Eq f, Ord v) => Term f v -> Term f v -> Maybe (Subst f v)
unify t u = do
let
act = do
t' <- mkNode t
u' <- mkNode u
success <- solve [(t', u')]
return (t', success)
(union, ((root, success), vmap)) = UM.run' $ runStateT act M.empty
succs n = case snd (U.lookup union n) of
VarA v -> []
FunA f ns -> ns
FunP f ts -> do v <- Term.vars =<< ts; maybeToList (M.lookup v vmap)
guard $ success && acyclic (U.size union) succs root
let
subst = fromMap $ fmap lookupNode vmap
terms = fmap mkTerm (UM.label union)
lookupNode = (terms !) . U.fromNode . fst . U.lookup union
mkTerm (VarA v) = Var v
mkTerm (FunA f ns) = Fun f (fmap lookupNode ns)
mkTerm (FunP f ts) = subst `apply` Fun f ts
return subst
acyclic :: Int -> (U.Node -> [U.Node]) -> U.Node -> Bool
acyclic size succs root = runST $ do
let t :: ST s (STUArray s Int Word8)
t = undefined
color <- newArray (0, size-1) 0 `asTypeOf` t
let dfs n = do
c <- readArray color (U.fromNode n)
case c of
0 -> do
writeArray color (U.fromNode n) 1
flip (foldr andM) (map dfs (succs n)) $ do
writeArray color (U.fromNode n) 2
return True
1 -> return False
2 -> return True
dfs root
andM :: Monad m => m Bool -> m Bool -> m Bool
andM a b = do
a' <- a
if a' then b else return False
unifyRef :: (Eq f, Ord v) => Term f v -> Term f v -> Maybe (Subst f v)
unifyRef t u = fromMap <$> go [(t, u)] M.empty where
go [] subst = Just subst
go ((t, u) : xs) subst = case (t, u) of
(Var v, t) -> add v t xs subst
(t, Var v) -> add v t xs subst
(Fun f ts, Fun f' ts')
| f /= f' || length ts /= length ts' -> Nothing
| otherwise -> go (zip ts ts' ++ xs) subst
add v t xs subst
| Var v == t = go xs subst
| occurs v t = Nothing
| otherwise =
let app = apply (fromMap (M.singleton v t))
in go (fmap (app *** app) xs) (M.insert v t (fmap app subst))
occurs v t = v `elem` Term.vars t