import Data.Char -- in order to use the function "toLower" data PrologVar = PrologVar Int instance Eq PrologVar where (PrologVar n) == (PrologVar m) = n==m instance Show PrologVar where show (PrologVar n) = "X"++(show n) data InitialAtomChar = InitalAtomChar Char instance Eq InitialAtomChar where (InitalAtomChar c1)==(InitalAtomChar c2) = (toLower c1)==(toLower c2) data PrologAtom = PrologAtom String instance Show PrologAtom where show (PrologAtom []) = error "no empty string atom allowed!" show (PrologAtom [c]) = show c show (PrologAtom (c:cs)) = show ((toLower c):cs) instance Eq PrologAtom where (PrologAtom s1) == (PrologAtom s2) = (s1==s2) type PrologFunSymb = PrologAtom data PrologTerm = Var PrologVar | Atom PrologAtom | Apply PrologFunSymb [PrologTerm] instance Eq PrologTerm where (Var pv1) == (Var pv2) = (pv1==pv2) (Atom pa1)== (Atom pa2) = (pa1==pa2) (Apply pfs1 pts1) == (Apply pfs2 pts2) = (pfs1==pfs2) && ((lenght pts1)==(lenght pts2)) && (eqList pts1 pts2) where eqList [] [] = True eqList (p1:ps1) (p2:ps2) = (p1==p2) && (eqList ps1 ps2) _ == _ = False instance Show PrologTerm where show (Var pv) = show pv show (Atom pa) = show pa show (Apply pfs args) = (show pfs)++"("++(showargs args)++")" where showargs [] = "" showargs [arg] = show arg showargs (arg:args) = (show arg)++","++(showargs args) -- examples of Prolog terms myPrologTerm1 = Apply (PrologAtom "g") [(Apply (PrologAtom "f") [Var (PrologVar 3),Var (PrologVar 3)]), (Var (PrologVar 2))] myPrologTerm2 = Apply (PrologAtom "g") [(Apply (PrologAtom "f") [Var (PrologVar 5),Var (PrologVar 3)]), (Apply (PrologAtom "h") [Var (PrologVar 6)] )] type PrologSubst = (PrologTerm -> PrologTerm) occur :: PrologVar -> PrologTerm -> Bool occur pv1 (Var pv2) = (pv1 == pv2) occur pv (Atom pa) = False occur pv (Apply pfs []) = False occur pv (Apply pfs (arg:args)) = (occur pv arg) || (occur pv (Apply pfs args) ) occur _ _ = error "First arg of occur must be a variable" lenght [] = 0 lenght (x:xs) = 1 + (lenght xs) identity x = x compose f g x = (f (g x)) mksubst :: PrologVar -> PrologTerm -> PrologSubst mksubst pv1 pt (Var pv2) = if (pv1 == pv2) then pt else (Var pv2) mksubst pv pt (Atom pa) = (Atom pa) mksubst pv pt (Apply pfs []) = Apply pfs [] mksubst pv pt (Apply pfs (arg:args)) = Apply pfs ((mksubst pv pt arg):(args >>= \t1 -> [((mksubst pv pt) t1)])) unify :: PrologTerm -> PrologTerm -> (Bool,PrologSubst) -- subst is identity when non unifiable unify (Var pv) pt | ((Var pv) == pt) = (True,identity) | (not (occur pv pt)) = (True,(mksubst pv pt)) unify (Atom pa1) (Atom pa2) = if (pa1 == pa2) then (True,identity) else (False,identity) unify (Atom pa) (Var pv) = unify (Var pv) (Atom pa) unify (Atom pa) _ = (False,identity) unify (Apply pfs args) (Atom pa) = (False,identity) unify (Apply pfs args) (Var pv) = unify (Var pv) (Apply pfs args) unify (Apply pfs1 args1) (Apply pfs2 args2) | ((pfs1==pfs2) && ((lenght args1)==(lenght args2))) = unifyList args1 args2 | otherwise = (False, identity) where unifyList [] [] = (True,identity) unifyList (a1:as1) (a2:as2) = (b1 && b2, (compose subst1 subst2)) where (b1,subst1) = (unify a1 a2) (b2,subst2) = (unifyList as1 as2)