Learning Prolog via Examples - Terms and Operators

 Part of INTERACTIVE PROLOG GUIDE  Prev TOC Next 


Term is a basic data structure in Prolog, i.e., everything including program and data is expressed in form of term. There are four basic types of terms in Prolog: variables, compound terms, atoms and numbers. The following picture shows the correlation between them as well as examples of corresponding terms:

term
 |-- var (X,Y)
 |
  -- nonvar (a,1,f(a),f(X))
       |-- compound (f(a),f(X))
       |
        -- atomic  (a,1)
             |-- atom (a)
             |
              -- number (1)


It is possible to use predicates var, nonvar, compound, atomic, atom and number to test the type of given term (see copy_term bellow). Prolog also provides build-in predicates to access structure of the nonvar terms as well to construct terms.

If one needs to copy a term (copy has the same structure as the original term but introduces new variables), it is possible to use predicate copy_term/2 which is build-in in most Prolog systems. However, it is straightforward to write a code of copy_term in Prolog using above mentioned predicates.

copy_term(A,B):-cp(A,[],B,_).

cp(A,Vars,A,Vars):-
   atomic(A).
cp(V,Vars,NV,NVars):-
   var(V),register_var(V,Vars,NV,NVars).
cp(Term,Vars,NTerm,NVars):-
   compound(Term),
   Term=..[F|Args],    % decompose term
   cp_args(Args,Vars,NArgs,NVars),
   NTerm=..[F|NArgs].  % construct copy term

cp_args([H|T],Vars,[NH|NT],NVars):-
   cp(H,Vars,NH,SVars),
   cp_args(T,SVars,NT,NVars).
cp_args([],Vars,[],Vars).

During copying one has to remeber copies of variables which can be used further during copying. Therefore the register of variable copies is maintained.

register_var(V,[X/H|T],N,[X/H|NT]):-
   V\==X,         % different variables
   register_var(V,T,N,NT).
register_var(V,[X/H|T],H,[X/H|T]):-
   V==X.          % same variables
register_var(V,[],N,[V/N]).

Here is an example that clarifies the notion of term copy:

f(X,g(X)) is copy of f(Y,g(Y)) but not of f(U,g(V)).


Unification

Unification is an engine of Prolog. It tries to fing most general substitution of variables in two terms such that after applying this substitution to both terms, the terms became the same. To unify terms A and B, one can easily invoke build-in unification A=B. Try to unify different terms to see what the notion "unification" really means. Again, it is straightworfard to write Prolog code of unification (we use '=' to test equality of two atomic terms or to unify variable with term only).

unify(A,B):-
   atomic(A),atomic(B),A=B.
unify(A,B):-
   var(A),A=B.            % without occurs check
unify(A,B):-
   nonvar(A),var(B),A=B.  % without occurs check
unify(A,B):-
   compound(A),compound(B),
   A=..[F|ArgsA],B=..[F|ArgsB],
   unify_args(ArgsA,ArgsB).

unify_args([A|TA],[B|TB]):-
   unify(A,B),
   unify_args(TA,TB).
unify_args([],[]).

Did you find out what is it "occurs check"? OK, try to unify the following terms X and f(X). What happens? Most Prolog systems will fill in the whole memory as they will try to construct infinite term f(f(f(...))) which should be the result of the unification. Such Prolog systems does not incorporate occurs check because of its time consuming nature. So, occurs check tests the occurence of the variable X in the term T (which is not a variable) during unification of X and T.


Operators

Writing terms in the form functor(arg1,arg2,...) is not often appropriate from the human point of view. Just compare the following two transcriptions of the same Prolog clause:

p(X,Z):-q(X,Y),r(Y,Z),s(Z).

':-'(p(X,Z),(','(q(X,Y),','(r(Y,Z),s(Z))))).

Which one do you prefer?

To simplify the entry of terms, Prolog introduces operators which enable "syntactic sugar", i.e., more natural way of writing terms. Operators are used with unary and binary terms only. They enable to set the location of functor (prefix, infix, postfix), the associative feature and, finally, the priority among operators.

op(Priority,Appearence,Name)
       |        |
       |         -- xfy, yfx, xfx, fx, fy, xf, yf
        -- the higher number the priority has, the lower priority

Instead of explaining the meaning of above definition, look at the following example.

op(400,yfx,'*').  % a*b*c means ((a*b)*c)
op(500,yfx,'+').
op(500,yfx,'-').  % be careful a-b-c means ((a-b)-c)
op(700,xfx,'=')   % it is not possible to write a=b=c
op(900,fy,not).   % one can write not not a and it means not(not(a))

not 1=2+3+4*5 is equivalent to:
     not(1=((2+3)+(4*5)))
     not('='(1,'+'('+'(2,3),'*'(4,5)))).

Note, that the numbers indicating priority can be different in miscellaneous implementations of Prolog (the numbers in above example are taken from Open Prolog for Macintosh).

Important!
The definition of operator is not a new program for operator but the "call" of the goal op. Thus, if you want to define an operator in the program, you write :-op(400,yfx,'*').


Terms make the basics of Prolog.


 Part of INTERACTIVE PROLOG GUIDE  Prev TOC  Next


Last update 21st November 1997
Designed and maintained by Roman Bartak
© November 1997