3_prolog_language
3_prolog_language
1
(ISO-)Prolog
3
Comparison with Imperative and Functional Languages
7
Prolog Syntax — Defining Operators
• Certain functors and predicate symbols are predefined as infix, prefix, or postfix
operators, aside from the standard term notation, and new ones can be added.
• Very useful to make programs and data files more readable!
• Stated using operator declarations:
:- op(< precedence >, < type >, < operator(s) >).
< precedence >: is an integer from 1 to 1200.
General rule: the operator with the highest precedence number is the principal functor.
E.g., if ‘+’ has higher precedence number than ‘/’, then
a+b/c ≡ a+(b/c) ≡ +(a,/(b,c)) .
Alternatively, we can always use parenthesis: /(+(a,b),c) ≡ (a+b)/c
(Note that in some other languages the ordering of precedence values is the opposite.)
< type >:
* infix: xfx (not associative), xfy (right associative), yfx (left associative).
* prefix: fx (non-associative), fy (associative).
* postfix: xf (non-associative), yf (associative).
< operator(s) >: can be a single atom or a list of atoms.
8
Prolog Syntax — Operators (Contd.)
• Examples:
Standard Notation Operator Notation
’+’(a,’/’(b,c)) a+b/c
is(X, mod(34, 7)) X is 34 mod 7
’<’(’+’(3,4),8) 3+4 < 8
’=’(X,f(Y)) X = f(Y)
’-’(3) -3
spy(’/’(foo,3)) spy foo/3
’:-’(p(X),q(Y)) p(X) :- q(Y)
’:-’(p(X),’,’(q(Y),r(Z))) p(X) :- q(Y),r(Z)
• Note that, with this syntax convention, Prolog clauses are also Prolog terms!
• Parenthesis must always be used for operators with higher priority than 1000
(i.e., the priority of ’,’): ..., assert( (p :-q)), ...
• Operators are local to modules (explained later).
9
Prolog Syntax — Operators (Contd.)
10
The Execution Mechanism of (classical) Prolog
• Always execute calls in the body of clauses left-to-right.
• When entering a procedure, if several clauses unify (a choice point), take the first
unifying clause (i.e., the leftmost unexplored branch).
• On failure, backtrack to the next unexplored clause of the last choice point.
grandparent (C,G) :- parent (C,P), parent (P,G).
grandparent(charles,X)
12
Built-in Arithmetic (Contd.) – The arithexpr type
arithexpr :=
| num
| + arithexpr | - arithexpr
| ++ arithexpr | -- arithexpr
| aritexpr + arithexpr | aritexpr - arithexpr
| aritexpr * arithexpr | aritexpr // arithexpr
| aritexpr / arithexpr | abs( arithexpr )
| sign( arithexpr ) | float_integer_part ( arithexpr )
| float ( arithexpr ) | float_fractional_part ( arithexpr )
| aritexpr ** arithexpr | exp( arithexpr )
| log( arithexpr ) | sqrt( arithexpr )
| sin( arithexpr ) | cos( arithexpr )
| atan( arithexpr ) | [ arithexpr ]
|. . .
Other arithmetic operators that can appear in arithmetic expressions (see manuals):
• rem, mod, gcd, >>, <<, /\, \/, \\, #, ...
• integer, truncate, floor, round, ceiling, ...
13
Built-in Arithmetic (Contd.)
• plus(X,Y,Z):- Z is X + Y.
Only works in one direction (X and Y bound to arithmetic terms).
Meta-logical tests (see later) allow using it in both directions.
We have lost the recursive structure of the numbers.
But we have won (a lot) in performance!
• Factorial:
Using Peano arithmetic: Using Prolog is/2 :
factorial (0,s(0)). factorial (0 ,1).
factorial (s(N),F) :- factorial (N,F) :-
factorial (N,F1), N > 0,
times (s(N),F1 ,F). N1 is N-1,
factorial (N1 ,F1),
F is F1*N.
• Wrong goal order can raise an error (e.g., moving last call to is/2 before call to
factorial).
15
Dynamic Checking of Basic Types
16
Type Checking Predicates (Contd.)
17
Structure Inspection
• functor(X, F, A) :
X is a term f(X1,...,Xn) → F=f A=n
F is the atom f and A is the integer n → X = f(X1,..,Xn)
Error if X, and either F or A are variables
Fails if the unification fails, A is not an integer, or F is not an atom
Examples:
18
Structure Inspection (Contd.)
• arg(N, X, Arg) :
N integer, X compound term → Arg unified with N-th argument of X.
Allows accessing a structure argument in constant time and in a compact way.
Error if N is not an integer, or if X is a free variable.
Fails if the unification fails.
Examples:
?- _T=date (9,’ February ’ ,1947) , arg (3,_T ,X).
X = 1947
?- _T=date (9,’ February ’ ,1947) , _T=date(_,_,X).
X = 1947
?- functor (Array ,array ,5) ,
arg (1,Array , black ),
arg (5,Array , white ).
Array = array (black ,_,_,_, white ).
• What does ?- arg(2,[a,b,c,d],X). return?
19
Example of Structure Inspection: Arrays
• Define add_arrays(A,B,C) :
add_arrays (A,B,C) :- % Same N below imposes equal length :
functor (A,array ,N), functor (B,array ,N), functor (C,array ,N),
add_elements (N,A,B,C).
add_elements (0,_,_,_).
add_elements (I,A,B,C) :-
I>0, arg(I,A,AI), arg(I,B,BI), arg(I,C,CI),
CI is AI + BI , I1 is I - 1,
add_elements (I1 ,A,B,C).
• In the latter case, where do we check that the three lists are of equal length?
20
Example of Structure Inspection: Arrays (Contd.)
add_elements (0,_,_,_).
add_elements (I,A,B,C) :-
I>0,
C@I is A@I + B@I ,
add_elements (I-1,A,B,C).
21
Example of Structure Inspection: Subterms of a Term
• Define subterm(Sub,Term) :
22
Higher-Order Structure Inspection
23
Conversion Between Strings and Atoms (New Atom Creation)
24
Meta-Logical Predicates
25
Meta-Logical Predicates (Contd.) – choosing implementations
create_list (0,[]).
create_list (N,[_|T]) :- N > 0, NT is N-1, create_list (NT ,T).
26
Meta-Logical Predicates (Contd.) – choosing implementations
create_list (0,[]).
create_list (N,[_|T]) :- N > 0, NT is N-1, create_list (NT ,T).
compute_length_ ([],N,N).
compute_length_ ([_|T],A,N) :- NA is A+1, compute_length_ (T,NA ,N).
27
Comparing Non-ground Terms
28
Comparing Non-ground Terms (Contd.)
• Compare with the same program with the second clause defined as
insert ([H|T], Item , [Item|T]):- H = Item.
29
Input/Output
30
Input/Output (Contd.)
31
Input/Output (Contd.)
• Example:
write_list_to_file (L,F) :-
telling ( OldOutput ), % Grab current output stream .
tell(F), write_list (L), % Write into F.
told , % Close .
tell( OldOutput ). % Reset previous output stream .
write_list ([]).
write_list ([X|Xs]):- write (X), nl , write_list (Xs).
• More powerful and format-based input-output predicates are available (see, e.g.,
format/2 and format/3 –Prolog system manuals).
• All these input-output predicates are “side-effects”!
32
Pruning Operator: Cut
• A “cut” (predicate !/0 ) commits Prolog to all the choices made since the parent
goal was unified with the head of the clause in which the cut appears.
• Thus, it prunes:
all clauses below the clause in which the cut appears, and
all alternative solutions to the goals in the clause to the left of the cut.
But it does not affect the search in the goals to the right of the cut.
s(1). p(X,Y):- l(X), ... r(8).
s(2). p(X,Y):- r(X), !, ... r(9).
p(X,Y):- m(X), ...
with query ?- s(A),p(B,C) .
If execution reaches the cut ( ! ):
The second alternative of r/1 is not considered.
The third clause of p/2 is not considered.
33
Pruning Operator: Cut (Contd.)
s(1). p(X,Y):- l(X), ... r(8).
s(2). p(X,Y):- r(X), !, ... r(9).
p(X,Y):- m(X), ...
| ?− s(A), p(B,C).
A/1 A/2
p(B,C) p(B,C)
l(B), ... r(B),!,... m(B), ... l(B), ... r(B),!,... m(B), ...
B/8 B/9 B/8 B/9
!,... !,...
34
“Types” of Cut
35
“Types” of Cut (Contd.)
• Red cuts: discard solutions which are not correct according to the intended
meaning.
Example:
max(X,Y,X):- X > Y,!.
max(X,Y,Y).
wrong answers to, e.g., ?- max(5, 2, 2).
Example:
days_in_year (X ,366) :- leap_year (X),!.
days_in_year (X ,365) .
leap_year (X):- number (X), 0 is X mod 4.
36
Meta-calls and Implementing Higher Order
• The meta-call call(X) converts a term X into a goal and calls it.
• When called, X must be instantiated to a term, otherwise an error is reported.
• Used for meta-programming, specially interpreters and shells.
Also for defining negation (as we will see) and implementing higher order.
• Example:
q(a). p(X) :- call(X).
?- p(q(Y)).
Y = a
• Example:
q(a,b). apply (F,Args) :- G =.. [F|Args], call(G).
?- G=q, apply (G,[Y,Z]).
Y = a
Z = b
• In Ciao the hiord package allows writing G(Y,Z) ; see also the hiordlib library.
37
Meta-calls – Aggregation Predicates
38
Meta-calls – Aggregation Predicates (Contd.)
39
Meta-calls – Aggregation Predicates: Examples
40
Meta-calls – Negation as Failure
• Uses the meta-call facilities, the cut and a system predicate fail that fails when
executed (similar to calling a=b ).
not(Goal) :- call(Goal), !, fail.
not(Goal).
• Available as the (prefix) predicate \+/1 : \+ member(c, [a,k,l])
• It will never instantiate variables.
Using \+ twice useful to test without binding variables. E.g., \+ \+ X = 1 ,
checks if X is bound (or can be bound) to 1, without binding X if is free.
• Termination of not(Goal) depends on termination of Goal . not(Goal) will
terminate if a success node for Goal is found before an infinite branch.
• It is very useful but dangerous:
unmarried_student (X):- not( married (X)), student (X).
student (joe).
married (john).
?- unmarried_student(X). → no
• Works correctly for ground goals (programmer’s responsibility to ensure this).
41
Meta-calls – Negation as Failure – Ensuring Correctness
• Or using assertions:
:- pred not(G) : ground (G).
not(G) :- \+ G.
I.e., we declare that G must be ground when called ( : field).
42
Cut-Fail
43
Dynamic Program Modification (I)
44
Dynamic Program Modification (II)
• Example program:
relate_numbers (X, Y):- assert ( related (X, Y)).
unrelate_numbers (X, Y):- retract ( related (X, Y)).
• Example query:
?- related (1, 2).
{ EXISTENCE ERROR : ...}
?- relate_numbers (1, 2).
yes
?- related (1, 2).
yes
?- unrelate_numbers (1, 2).
yes
?- related (1, 2).
no
45
Dynamic Program Modification (III)
• Example program:
fib (0, 0). lfib(N, F):- lemma_fib (N, F), !.
fib (1, 1). lfib(N, F):-
fib(N, F):- N > 1,
N > 1, N1 is N - 1,
N1 is N - 1, N2 is N1 - 1,
N2 is N1 - 1, lfib(N1 , F1),
fib(N1 , F1), lfib(N2 , F2),
fib(N2 , F2), F is F1 + F2 ,
F is F1 + F2. assert ( lemma_fib (N, F)).
:- dynamic lemma_fib /2.
lemma_fib (0, 0).
lemma_fib (1, 1).
“Those who cannot remember the past are condemned to repeat it” 46
Meta-Interpreters
• clause(<head>,<body>)
Reads a clause head :- body from the program.
For facts body is true .
• To use clause/2 a predicate must be declared dynamic .
• Simple (“vanilla”) meta-interpreter:
solve (true).
solve ((A,B)) :- solve (A), solve (B).
solve (A) :- clause (A,B), solve (B).
Some sample queries:
?- solve ( lappend ([1,2],[3,4],L)).
?- solve ( lappend (X,Y,[1,2,3,4])).
• This code also implements backtracking! Note that clause/2 introduces
choice-points since A can unify with several clause heads.
• Interactions with module system: remember that clauses must be dynamic (and
use the dynamic clauses package).
47
Meta-Interpreters: extending the basic meta-interpreter
48
Incomplete Data Structures
49
Playing with difference lists
• Create two difference lists ( L1 and L2 ) and append them ( L2=X ) “by hand”:
?- append_dl ([1,2,3|X]-X,[4,5|Y]-Y,L).
L = [1,2,3,4,5|Y]-Y, X = [4,5|Y] ?
L has the resulting (appended) difference list.
But note that we have modified the first list: we cannot append to it again.
?- append_dl (L-X,[4,5|Y]-Y,[1,2,3,4,5|Z]-Z).
L = [1,2,3,4,5|Y], X = [4,5|Y], Z = Y ?
50
Standard qsort (using append)
qsort ([],[]).
qsort ([X|L],S) :-
partition (L,X,LS ,LB),
qsort (LS ,LSS),
qsort (LB ,LBS),
append (LSS ,[X|LBS],S).
51
qsort w/Difference Lists (no append!)
qsort_dl (L,SL) :-
qsort_dl_ (L,SL ,[]).
article ([a]).
article ([t,h,e]).
noun([c,a,r]).
noun([p,l,a,n,e]).
verb([f,l,i,e,s]).
verb([d,r,i,v,e,s]).
54
Parsing (using standard clauses and difference lists)
?- myphrase([t,h,e,’ ’,p,l,a,n,e,’ ’,f,l,i,e,s],[]).
myphrase (X,CV) :-
article (X,CA), spaces (CA ,CS1), noun(CS1 ,CN),
spaces (CN ,CS2), verb(CS2 ,CV).
article ([a|X],X).
article ([t,h,e|X],X).
noun([c,a,r | X],X).
noun([p,l,a,n,e | X],X).
verb([f,l,i,e,s | X],X).
verb([d,r,i,v,e,s | X],X).
55
Parsing (same, using some string syntax)
?- myphrase("the plane flies",[]).
myphrase (X,CV) :-
article (X,CA), spaces (CA ,CS1), noun(CS1 ,CN),
spaces (CN ,CS2), verb(CS2 ,CV).
:- use_package (dcg).
57
Parsing + actions (calling Prolog in DCGs)
• Other actions can be interspersed with the grammar.
Raw Prolog can be called (between “{ ... }”)
:- use_package (dcg).
myphrase (N) --> article (AC), spaces (S1), noun(NC), spaces (S2),
verb(VC), { N is AC + S1 + NC + S2 + VC}.
noun (3) --> "car". verb (5) --> " flies ".
noun (5) --> " plane ". verb (6) --> " drives ".
58
Other issues in Prolog (see “The Art of Prolog” and Bibliography)
• Repeat loops.
main(_) :- repeat , read(X), process (X).
process (end).
process (X) :- display (X), fail.
• Exception handling.
• Extending the syntax beyond operators: term expansions/macros →packages.
• Delay declarations/concurrency.
• Operating system interface (and sockets, etc.).
• Foreign language (e.g., C) interfaces.
• Many other built-ins...
• ...
59
Some Typical Libraries in Prolog Systems
60
Some Additional Libraries and Extensions (Ciao)
Other systems may offer additional extensions. Some examples from Ciao:
• Other execution rules:
Breadth-first, Iterative-deepening, Random, ...
Tabling
CASP (negation with multiple models)
Andorra (“determinate-first”) execution, fuzzy Prolog, ...
• Interfaces to other languages and systems:
Interfaces to C, Java, JavaScript, Python, LLVM, ...
SQL database interface and persistent predicates
Web/HTML/XML/CGI programming (PiLLoW) / HTTP connectivity / JSON /
compilation to JavaScript ...
Interfaces to solvers (PPL, Mathematica, MiniSAT, Z3, Yikes, ...)
Graphviz, daVinci interfaces
Interfaces to Electron, wxWidgets, Tcl/Tk, VRML (ProVRML), ...
Calling Emacs from Prolog, etc.
61
Some Additional Libraries and Extensions (Ciao, Contd.)
62
Some Additional Libraries and Extensions (Ciao, Contd.)
63