packages feed

tableaux-0.1: src/Unify.hs

{- 
   Robinson's unification algorithm for first order terms
   Pedro Vasconcelos, 2009
   pbv@dcc.fc.up.pt
 -}
module Unify(unifyEqs) where

import FOL  
import qualified Data.Map as Map

-- unification algorithm
-- the inputs are the current unifier substitution
-- and a list of pairs of terms to unify (i.e. equations)
unifyEqs :: Subst -> [(Term,Term)] -> Maybe Subst
unifyEqs s [] = return s 
unifyEqs s ((t,t'):eqs) = unifyEqs' s (subst s t) (subst s t') eqs

-- auxiliary function
-- pre-condition: the unifying substitution has already been applyed
unifyEqs' :: Subst -> Term -> Term -> [(Term,Term)] -> Maybe Subst
unifyEqs' s (Var x) (Var y) eqs 
    | x==y      = unifyEqs s eqs
    | x<y       = unifyEqs (s `extend` (y,Var x)) eqs
    | otherwise = unifyEqs (s `extend` (x,Var y)) eqs
unifyEqs' s (Var x) t eqs 
    | x`notElem`fv t = unifyEqs (s `extend` (x,t)) eqs
    | otherwise      = fail "occur check failed"

unifyEqs' s t (Var x) eqs = unifyEqs' s (Var x) t eqs

unifyEqs' s (Fun f ts) (Fun f' ts') eqs
    | f==f' && length ts==length ts' = unifyEqs s (zip ts ts' ++ eqs)
    | otherwise                      = fail "unification failed" 

-- note that "fail" for the Maybe monad is Nothing


-- extend a substitution
extend :: Subst -> (Var,Term) -> Subst
s `extend` (v,t) = Map.insert v t s 

-- compose two substitutions
-- note that Map.union is left-biased
-- compose :: Subst -> Subst -> Subst
-- compose s2 s1 = Map.map (subst s2) s1 `Map.union` s2


-- restrict a substitution
-- remove bindings for a list of variables
-- restrict :: Subst -> [Var] -> Subst
-- s `restrict` vs = foldr Map.delete s vs