/tmp/mosstmp/csu01127/unify.sml

datatype Term = VAR of string
	| CONST of string
	| OPR1 of string * Term
	| OPR2 of string * Term * Term
	| OPR3 of string * Term * Term*Term

(*checks if the term is a variable or not*)
fun isvar(CONST(c:string))=false
        |isvar(VAR(x:string))=true
        |isvar(OPR1(f,a))=false
        |isvar(OPR2(f,a,b))=false
        |isvar(OPR3(f,a,b,c))=false;

(*compares 2 terms for equality*)
fun comp2(CONST(c1),CONST(c2))=if c1=c2 then true else false
	|comp2(VAR(x),VAR(y))=if x=y then true else false
	|comp2(OPR1(f,a),OPR1(g,b))=if f=g then comp2(a,b) else false
	|comp2(OPR2(f,a,b),OPR2(g,c,d))=if f=g then comp2(a,c) andalso comp2(b,d) else false
	|comp2(OPR3(f,a,b,c),OPR3(g,p,q,r))=if f=g then comp2(a,p) andalso comp2(b,q) andalso comp2(c,r) else false

(*checks if the variable is present in the given term , called only after checking fo variable *)
fun ispresent(VAR(x):Term,CONST(c))=false
	|ispresent(VAR(x),VAR(y))=if x=y then true else false
other	|ispresent(VAR(x),OPR1(f,a))=ispresent(VAR(x),a)
	|ispresent(VAR(x),OPR2(f,a,b))=ispresent(VAR(x),a) andalso ispresent(VAR(x),b) 
	|ispresent(VAR(x),OPR3(f,a,b,c))=ispresent(VAR(x),a) andalso ispresent(VAR(x),b) andalso ispresent(VAR(x),c);


(* the replacement set , contains the pair of variables replaced and term by which replaced *)
val z=[(VAR("a"),VAR("b"))];

(* replaces all instances of the variable x by the term p in the given term *)
fun repvar(CONST(c),p:Term,x:string)=CONST(c)
	|repvar(VAR(a),p,x)=if a=x then p else VAR(a)
	|repvar(OPR1(f,a),p,x)=if isvar(a) then if a=VAR(x) then OPR1(f,p)
						else OPR1(f,a)
				else OPR1(f,repvar(a,p,x))
	|repvar(OPR2(f,a,b),p,x)=if isvar(a) then if  a= VAR(x) then OPR2(f,p,repvar(b,p,x))
						  else OPR2(f,a,repvar(b,p,x))
				 else if isvar(b) then if  b=VAR(x) then OPR2(f,repvar(a,p,x),p)
						       else OPR2(f,repvar(a,p,x),b)
				 else OPR2(f,repvar(a,p,x),repvar(b,p,x))
	|repvar(OPR3(f,a,b,c),p,x)=if isvar(a) then if a=VAR(x) then OPR3(f,p,repvar(b,p,x),repvar(c,p,x)) 
						    else OPR3(f,a,repvar(b,p,x),repvar(c,p,x))
				   else if isvar(b) then if b=VAR(x) then OPR3(f,repvar(a,p,x),p,repvar(c,p,x)) 
							 else OPR3(f,repvar(a,p,x),b,repvar(c,p,x))
				   else if isvar(c) then if c=VAR(x) then OPR3(f,repvar(a,p,x),repvar(b,p,x),p) 
							 else OPR3(f,repvar(a,p,x),repvar(b,p,x),c)
				   else OPR3(f,repvar(a,p,x),repvar(b,p,x),repvar(c,p,x));

(* replaces the variable x by the term p in the whole term list given along *)
fun repvarall([]:Term list,p:Term,VAR(x):Term,z)=[]
	|repvarall(a::[],p,VAR(x),z)=repvar(a,p,x)::[]
	|repvarall(a::l,p,VAR(x),z)=repvar(a,p,x)::repvarall(l,p,VAR(x),z);


(* finds the term where unification can take place*)
(* then calls repvarall to replace the term in the whole of list *)
(* returns the term list after replacing*)
(* also adds the term that is being replaced with the one replacing ,in  z*)
fun match2(CONST(c1),CONST(c2),t:Term list)=t
	|match2(VAR(x),CONST(c),t)=t
	|match2(VAR(x),VAR(y),t)=repvarall(t,VAR(y),VAR(x),(VAR(x),VAR(y))::z)
	|match2(VAR(x),OPR1(f,a),t)=if not(ispresent(VAR(x),OPR1(f,a))) then repvarall(t,OPR1(f,a),VAR(x),(VAR(x),OPR1(f,a))::z) else t
	|match2(VAR(x),OPR2(f,a,b),t)=if not(ispresent(VAR(x),OPR2(f,a,b))) then repvarall(t,OPR2(f,a,b),VAR(x),(VAR(x),OPR2(f,a,b))::z) else t
	|match2(VAR(x),OPR3(f,a,b,c),t)=if not(ispresent(VAR(x),OPR3(f,a,b,c))) then repvarall(t,OPR3(f,a,b,c),VAR(x),(VAR(x),OPR3(f,a,b,c))::z) else t
	|match2(OPR1(f,a),OPR1(g,b),t)=if f=g then if isvar(a) then if not(ispresent(a,b)) then repvarall(t,b,a,(a,b)::z)  
								    else t 
						   else match2(a,b,t)
					else t
	|match2(OPR2(f,a,b),OPR2(g,c,d),t)=if f=g then if isvar(a) then if not(ispresent(a,c)) then match2(b,d,repvarall(t,c,a,(a,c)::z))
									else t
						       else match2(b,d,match2(a,c,t)) 
					   else t
	|match2(OPR3(f,a,b,c),OPR3(g,p,q,r),t)=if f=g then if isvar(a) then if not(ispresent(a,p)) then match2(b,q,match2(c,r,repvarall(t,p,a,(a,p)::z)))
									    else t
							   else match2(b,q,match2(c,r,match2(a,p,t)))
						else t;

(* returns the arity of the term *)
fun arity(CONST(c):Term)=0
	|arity(VAR(x))=1
	|arity(OPR1(f,a))=2
	|arity(OPR2(f,a,b))=3
	|arity(OPR3(f,a,b,c))=4

(* cleans up the list of the possible duplication and then returns the cleaned list *)
fun cleanup1([]:Term list,t:Term,l:Term list)=l
	|cleanup1(a::[],t,l)=[a]
	|cleanup1(a::b::x,t,l)=if comp2(a,t) then cleanup1(b::x,t,l) else cleanup1(b::x,t,a::l);

fun cleanup2([]:Term list,l:Term list)=l
	|cleanup2(a::[],l)=cleanup2([],cleanup1(l,a,[]))
	|cleanup2(a::b::x,l)=cleanup2(b::x,cleanup1(l,a,[]));

(* checks if the term t can be replaced *)
(* then calls the match2 for the replacement *)
(*returns the term list after checking *)
fun part1(t:Term,[]:Term list)=[]
	|part1(t,a::[])=if arity(a)=arity(t) then match2(t,a,a::[]) else [a]
	|part1(t,a::b::x)=if arity(a)=arity(t) then part1(t,cleanup2(match2(t,a,a::b::x)@part1(t,b::x),match2(t,a,a::b::x)@part1(t,b::x))) 
			  else a::b::x;

(* runs the function part1 for all terms in the given list *)
fun unify2([]:Term list,l:Term list)=l
	|unify2(a::[],l)=[a]
	|unify2(a::b::x,l)=unify2(b::x,part1(a,l));

(*the first term is checked for unification with other term in the list *)
(*if possible then replacement and cleanup are done for this term *)
(*if not then the other terms are also checked in the same way *)
(* returns the term list containing the non unifiable terms*)
(* if all of them unify then "z" has the pairs of replaced terms with the replacing term *)

fun unify(l:Term list)=unify2(l,l);