Prolog
introduction
basic constructs
the basic constructs of prolog are terms and statements
terms - atoms
the simplest term is an atom, the following are atoms:
john
$<@
'an atom'
an atom is
- a string of letters, digits, and an underscore starting with a lower-case letter:
anna
x_25
nil
- a string of special characters (
+ - * / < > = : . & _ ~
):$<@
<---->
.:.
- a string of characters enclosed in single quotes:
'Tom'
'2A$'
terms - numbers
- integers:
123
-42
- real numbers:
3.14
-0.573
2.4e3
terms - variables
a variable is a string of letters, digits and an underscore starting with an upper-case letter or an underscore
X_25
_result
compound terms
a compound term comprises a functor and arguments
course(236319, pl)
a functor f
of arity n
is denoted f/n
terminology
- a term is ground (קונקרטי) if it contains no variables
- a goal is an atom or a compound term
- a predicate (פרדיקט) is a functor for which a list of clauses is defined
- a clause (פסוקית) is a fact or a rule
facts
a fact (עובדה) is a kind of statement
eats(bunny, carrot).
this fact states that the predicate eats
holds for the atoms bear
and honey
facts can have any arity
summer.
sad(john).
plus(2, 3, 5).
a finite set of facts constitutes a program
mammal(rat).
mammal(bear).
fish(salmon).
eats(bear, honey).
eats(bear, salmon).
eats(rat, salmon).
eats(salmon, warm).
facts can contain variables
likes(X, course236319).
variables are universally quantified
\[\forall X,likes(X, course236319)\]queries
a query (שאילתה) is a conjunction of goals
?- eats(X, salmon), eats(X, honey).
variables are existentially quantified
\[\exists X,eats(X, salmon) \land eats(X, honey)\]rules
a rule (חוק, כלל) is a statement which enables us to define new relationships in terms of existing ones
predicate(term1, ..., termN) :- goal1, ..., goalN.
Y
is a survival dependency of X
if:
X
eatsY
- or
X
eatsZ
andY
is a survival dependency ofZ
survival_dependency(X, Y) :- eats(X, Y).
survival_dependency(X, Y) :-
eats(X, Z), survival_dependency(Z, Y).
?- survival_dependency(bear, X).
writing Prolog programs
- create a file named
prog.pl
- write clauses in
prog.pl
- enter the prolog interpreter
- type
consult(prog.pl)
- query the interpreter
dynamic clauses
you can add clauses dynamically
:- assertz(eats(bear, tuna)).
:- assertz((
mother(Child, Mother) :-
parent(Child, Mother),
female(Mother)
)).
?- eats(bear, tuna).
asserta
asserts the clause as first clause of the predicate while assertz
asserts it as last clause
dynamically remove a clause using retract/1
:- assertz(q(a)).
:- assertz((p(X) :- q(X))).
:- assertz(p(b)).
:- retract(p(X) :- q(a)).
?- p(a).
dynamically remove clauses using retractall/1
:- assertz(q_2(a)).
:- assertz((p_2(X) :- q_2(X))).
:- assertz(p_2(b)).
:- retractall(p_2(_)).
?- p_2(a).
?- p_2(b).
dynamically remove a predicate using abolish/1
:- assertz(p(a)).
:- assertz(p(b)).
:- abolish(p/1).
?- p(X).
meaning of a prolog program
- declarative meaning
- the inference algorithm is an implementation detail
- not always easy to achieve
- procedural meaning
- but thinking procedurally makes it harder to come up with an elegant solution
- beats the purpose of the paradigm
matching
two terms match if:
- they are identical
- the variables in both terms can be instantiated to make the terms identical
the operator =
performs matching
?- course(N, S, 95) = course(X, fall, G).
?- course(N, S, 95) = course(Y, M, 96).
?- course(X) = semester(Y).
matching rules
terms S
and T
match if:
S
andT
are the same atomS
andT
are the same number- if one is a variable it’s instantiated to the other
- if
S
andT
are compound terms, they match iff:- they have the same functor and arity
- all their corresponding arguments match
- the variable instantiations are compatible
geometric example
use compound terms to represent geometric shapes
point(1, 1)
seg( point(1, 1), point(2, 3) )
triangle( point(4, 2), point(6, 4), point(7, 1) )
?- triangle(point(1, 1), A, point(2, 3))
=
triangle(X, point(4, Y), point(2, Z)).
matching as means of computation
facts:
vertical(seg(
point(X, Y1),
point(X, Y2)
)).
queries:
?- vertical(seg(point(1, 1), point(1, 2))).
?- vertical(seg(point(1, 1), point(2, Y))).
?- vertical(seg(point(2,3), P)).
arithmetic
- the operators
+ - * / div mod
are (infix) binary relations - but they are arithmetic operators after the operator
is
?- X = 1 + 2.
?- X is 1 + 2.
comparison operators
X > Y
X < Y
X >= Y
X =< Y
X =:= Y % equal
X =\= Y % not equal
the comparison operators also force evaluation
?- 11 * 6 = 66.
?- 11 * 6 =:= 66.
=
VS. =:=
=
is used for matching and may instantiate variables=:=
causes an arithmetic evaluation of its operands and cannot instantiate variables
?- 1 + X = Y + 2.
?- 1 + X =:= Y + 2.
GCD
gcd(X, X, X).
gcd(X, Y, D) :-
X < Y,
Y1 is Y - X,
gcd(X, Y1, D).
gcd(X, Y, D) :-
Y < X,
gcd(Y, X, D).
?- gcd(12, 30, D).
builtin control predicates
conjunction ,/2
the goal (G1, G2)
succeeds if G1
and G2
succeed
disjunction ;/2
the goal (G1 ; G2)
succeeds if G1
or G2
succeed
defined as follows:
(G1 ; G2) :- G1.
(G1 ; G2) :- G2.
true
the predicate true/0
always succeeds
false
the predicates false/0
and fail/0
always fail
negation as failure
- the negation predicate is
\+/1
- for known predicates, prolog works under a closed world assumption - if something can’t be proved then it is false
- it is not logical negation!
person(jimmy).
person(cindy).
?- person(rick).
?- \+ person(rick).
it might not work like you’d expect
?- person(X).
?- \+ person(X).
why doesn’t prolog answer with X = rick
or simply with true
?
person(X)
succeeds so its negation fails
- if
G
fails\+ G
succeeds - if
G
succeeds\+ G
fails
\+/1
allows for non-monotonic reasoning - a fact can become false by adding clauses to the database
illegal(murder).
legal(X) :- \+ illegal(X).
illegal(theft).
?- legal(theft).
exercise - family tree
you have a database with the following predicate
parent(X, Y). % X is Y's parent
% examples:
parent(adam, cain).
parent(eve, cain).
parent(cain, enoch).
define a predicate grandparent(X)
that holds when X
is a grandparent
...
?- grandparent(X).
grandparent(X) :- parent(X, Y), parent(Y, _).
define a predicate nuclear(X, Y)
that holds when X
and Y
are in the same nuclear family
a nuclear family consists of 2 parents and their common children
...
?- nuclear(adam, X).
nuclear(X, Y) :- % siblings
parent(P1, X), parent(P2, X),
parent(P1, Y), parent(P2, Y),
\+(P1 = P2). % alternatively: `P1 \= P2`
nuclear(X, Y) :-
parent(X, C), parent(Y, C).
nuclear(X, Y) :-
(parent(X, Y); parent(Y, X)).
exercise - binary trees
we represent binary trees as terms:
nil
is the empty treenode(N, Tl, Tr)
is a tree node whereN
is some number andTl
andTr
are binary trees
define a predicate tree_size(T, S)
such that T
is a binary tree and S
is its size
...
?- tree_size(node(1,
node(2,
nil,
nil
),
node(3,
node(4, nil, nil),
nil
)),
S).
tree_size(nil, 0).
tree_size(node(_, Tl, Tr), S) :-
tree_size(Tl, Sl),
tree_size(Tr, Sr),
S is Sl + Sr + 1.
define a predicate tree_max(T, M)
such that T
is a binary tree and M
is the max of the values of T
’s nodes
you may use the arithmetic function max/2
...
?- tree_max(node(10,
node(-3,
nil,
nil
),
node(14,
node(4, nil, nil),
nil
)),
M).
tree_max(node(N, nil, nil), N).
tree_max(node(N, nil, Tr), M) :-
tree_max(Tr, Mr), M is max(N, Mr).
tree_max(node(N, Tl, nil), M) :-
tree_max(Tl, Ml), M is max(N, Ml).
tree_max(node(N, Tl, Tr), M) :-
tree_max(Tl, Ml),
tree_max(Tr, Mr),
M is max(N, max(Ml, Mr)).
define a predicate perfect_tree(T, H)
such that T
is a perfect binary tree and H
is its height
a node’s value should be its height
a perfect binary tree is a binary tree in which all interior nodes have two children and all leaves have the same depth
...
?- perfect_tree(T, 2).
perfect_tree(nil, 0).
perfect_tree(node(H, Tl, Tl), H) :-
H > 0,
H1 is H - 1,
perfect_tree(Tl, H1).