Before you can start: * Read the lab instructions

advertisement
Before you can start:
* Read the lab instructions
* Add module file (prog/sicstus/3.11.2 or higher)
* Modify your .emacs (see course page)
Using the system:
* Separate code (file.pl) and query (*prolog*)
buffers: all facts and rules in file.pl
* Open or create filename.pl to enter prolog mode
(after modifying .emacs and restarting emacs)
* Save file and press C-c C-b to “consult” buffer
and create the query window
* Quit command: “halt.”
Strict deadline 20 Dec. for labs (if you miss it,
you have to wait for the next re-examination)
Prolog syntax:
Constants: lower case first letter (a, anna, aX)
Variables: upper case first letter (X, Xs)
Special “ignored” variables: _ as first letter
A fact:
mother(anna, bob). %”anna is mother of bob”
created(god, _).
%”’god created X’ is true
% for any value of X”
A rule:
grandparent(X,Z) :parent(X,Y), parent(Y,Z).
A query (“goal”):
grandparent(X,julia). (written in *prolog* buffer)
Usually written:
:- grandparent(X, julia).
...in the material to distinguish from facts.
Further extensions (lists, functors, etc) later
Ex 1: Basic usage
Contents of .pl file:
mother(anna,bertil).
father(adam,bertil).
father(arne,beata).
mother(beata,christina).
father(bertil,cecilia).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
grandfather(X,Y) :father(X,Z),
parent(Z,Y).
Queries (goals):
| ?- mother(anna,bertil).
yes
| ?- parent(X,bertil).
X = anna ? ;
X = adam ? ;
no
| ?- grandfather(X,Y).
X = adam,
Y = cecilia ? ;
X = arne,
Y = christina ? ;
no
Example 2: More usage
Contents of .pl file:
and(0,0,0). and(0,1,0). and(1,0,0). and(1,1,1).
or(0,0,0). or(0,1,1). or(1,0,1). or(1,1,1).
not(0,1). not(1,0).
circuit(X1,X2,X3,X4,Out) :and(X1, X2, Y1),
not(X3, Y2),
or(Y2,X4,Y3),
not(Y3,Y4),
or(Y1,Y4,Out).
Example queries:
?- circuit(0,1,0,1,Out).
Out = 0 ?
yes
?- circuit(A,B,C,D,1).
A
B
C
D
=
=
=
=
0,
0,
1,
0 ? ;
A
B
C
D
=
=
=
=
0,
1,
1,
0 ?
yes
(“Fill in the blanks” computation)
Prolog computation order
Prolog works by constructing an SLD-derivation:
1. Select the first atom of the goal.
2. Select the first untried rule or fact for the
same predicate as this atom. If none remain,
the current line of derivation has failed;
backtrack to a higher level.
3. Unify the atom and the head of the rule/fact.
If this fails, return to 2.
4. Apply the mgu to the body of the rule. Replace
the selected atom in the goal with the result
(keep the rest of the goal).
Note: A fact has an empty body.
5. If the new goal is empty, we have a successful
refutation (ie, an answer). Otherwise, start
again from 1 with the new goal (recursively).
Debug output (activate with command “trace.”) pauses
derivation and prints a message each time:
* Step 1 is reached
* Step 2 fails
* Step 4 succeeds
The unification is invisible.
(Deactivate tracing with “notrace.”)
Ex 3: Lists
[X,2,c] is a list with three elements
[] is the empty list
[X|Xs] is (cons X Xs) from Lisp
Note: [1,2,3] is syntactic sugar
[1|[2|[3|[]]]] is the “real” form
Contents of .pl file:
%member(X,L): Does the list L contain X?
member(X,[X|_]).
member(X,[_|L]) :- member(X,L).
Queries:
| ?- member(X,[1,2,3]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
no
| ?- member(a,L).
L = [a|_A] ? ;
L = [_A,a|_B] ?
yes
-- note: list with *at least*
one element (_A is a list)
-- L has at least two elements
(_A is an item, _B is a list)
Ex 4: Some arithmetics
X = Y+Z: Unifies X with +(Y,Z) without performing
any calculation (eg. ‘6=5+1’ fails).
X is E: Calculate expression E, then unify.
‘X is 5+1’ results in X=6; ‘X is Y+Z’
requires that Y and Z are numbers (or
expressions containing numbers, eg. Y=2*3)
E1<E2, E1=<E2, E1>=E2, E1>E2: Compare expressions
E1=:=E2: Expressions E1 and E2 have the same value
“2*3 = 3*2” false, “2*3 =:= 3*2” true
E1=\=E2: Expressions E1 and E2 have different values
Code:
fac(0,1).
fac(N,F) :N>0,
M is N-1,
fac(M,G),
F is G*N.
Queries:
| ?- fac(3,F).
F = 6 ?
yes
| ?- fac(N,6).
{INSTANTIATION ERROR: _51>0 - arg 1}
Ex 5: Recursion: Order matters
Code:
(Same ’parent’ relation as in ex 1)
ancestor1(X,Y) :- parent(X,Y).
ancestor1(X,Y) :parent(X,Z),
ancestor1(Z,Y).
ancestor2(X,Y) :- parent(X,Y).
ancestor2(X,Y) :ancestor2(X,Z),
parent(Z,Y).
Queries:
| ?- ancestor1(X,cecilia).
X = bertil ? ;
X = anna ? ;
X = adam ? ;
no
| ?- ancestor2(X,cecilia).
X = bertil ? ;
X = anna ? ;
X = adam ? ;
(Infinite loop!)
Ex 6: Useful builtins
length(L,N): L is a list with length N
setof(X,p(X),Set)
bagof(X,p(X),Bag)
Set of all results to query p(X)
“Bag” of all results to query p(X)
| ?- setof(X,member(X,[b,a,c,a]),Set).
Set = [a,b,c] ?
-- sorted, unique members
yes
| ?- bagof(X,member(X,[b,a,c,a]),Bag).
Bag = [b,a,c,a] ? -- all answers in returned order
yes
Negation
\+p(X,Y): p(X,Y) has no solutions
| ?- parent(anna,adam).
no
| ?- \+ parent(anna,X).
no
| ?- \+ parent(X,X).
true ?
yes
\+(X=Y) is written “X\=Y”: “X,Y can’t be equal”
(Negation is covered in more detail in Ulf’s
lectures!)
Ex 7: data types
Code:
birthday(anna, date(feb,20)).
birthday(arne, date(jun,15)).
birthday(beata, date(feb,10)).
birthday(bertil, date(oct,20)).
Queries:
| ?- birthday(anna,X).
X = date(feb,20) ?
yes
| ?- birthday(X,date(feb,Y)).
X = anna,
Y = 20 ? ;
X = beata,
Y = 10 ? ;
no
| ?- birthday(X, Date), birthday(Y, Date), X\=Y.
no
Also nested: tree(tree(1,2), 3)
Fully handled by unification
Ex 8: More data type usage
Define the tree type:
tree(N) :number(N).
tree(tree(L,R)) :tree(L),
tree(R).
Searching procedure:
treecontains(X,X).
treecontains(tree(L,_R), X) :treecontains(L,X).
treecontains(tree(_L,R), X) :treecontains(R,X).
Possibly unexpected query effects:
| ?- treecontains(tree(tree(1,2),3),X).
X = tree(tree(1,2),3) ? ;
X = tree(1,2) ?;
X = 1?
| ?- treecontains(T,1).
T = 1 ? ;
T = tree(1,_A) ?
| ?- tree(T).
(infinite loop: number(X) doesn’t generate numbers)
Hints and reminders
* There are no “return values”! Using the result
of a predicate is done by reusing variables:
do_something(Input, Output) :find_thing(Input, Thing),
process(Thing, Output).
* The effect of a predicate in the body of a rule
is exactly that the variables of the predicate
are instantiated.
(Sometimes they are “instantiated” into another
variable, or a data type containing variables).
* ‘X=Y’ unifies; ‘X is Y+1’ evaluates Y+1.
* Make the head of a rule as specific as possible
(‘fac(0,1)’ rather than ‘fac(N,X) :- N=0, X=1’)
* Each fact and rule should be literally correct,
taken as a statement by itself
Download