Prolog Tutorial
Prolog Tutorial
Programming in Logic
with some mention of Datalog and
Constraint Logic Programming
Very nice, though faster ones are for sale (e.g., SICSTUS Prolog).
Logic programming
(e.g., Prolog)
Constraint logic
programming
(e.g., ECLiPSe)
Efficient:
Variable ordering
Value ordering
Constraint joining and
propagation
Expressive:
Subroutines
Recursion
Variable domains are
terms (including lists
and trees)
But:
Simple, standard
solver: backtracking
and unification
Combo:
Tries to combine best
of both worlds
Later on well see how
But:
Encoding is annoying
Variables limited to
finite sets, ints, reals
Prolog as constraint
programming
(Person, Food)
Food
sam
dal
sam
curry
josie
samosas
josie
curry
rajiv
burgers
Person
eats(sam, dal).
eats(sam, curry).
eats(rajiv, burgers).
eats(josie, samosas).
eats(josie, curry).
eats(rajiv, dal).
Now it acts like a subroutine! At the Prolog prompt you can type
eats(sam, dal).
eats(josie, samosas).
eats(sam, curry).
eats(josie, curry).
eats(rajiv, burgers).
eats(rajiv, dal).
Now at the Prolog prompt you can type
start with
solutions where
Person1=sam,
Person2=sam.
How to fix?
6
eats(sam, dal).
eats(sam, curry).
eats(rajiv, burgers).
eats(josie, samosas).
eats(josie, curry).
eats(rajiv, dal).
answer
7
eats(sam, dal).
eats(josie, samosas).
eats(sam, curry).
eats(josie, curry).
eats(rajiv, burgers).
eats(rajiv, dal).
Now at the Prolog prompt you can type
start with
solutions where
Person1=sam,
Person2=sam.
How to fix?
8
Queries in Prolog
These things you type at the prompt are called queries.
Prolog answers a query as Yes or No
according to whether it can find a satisfying assignment.
If it finds an assignment, it prints the first one before printing Yes.
You can press Enter to accept it, in which case youre done,
or ; to reject it, causing Prolog to backtrack and look for another.
[ press ; ]
Person1=sam, Person2=josie, Food=curry
Person1=josie, Person2=sam, Food=curry
600.325/425 Declarative Methods
- J. Eisner
eats(sam, dal).
eats(josie, samosas).
eats(sam, curry).
eats(josie, curry).
eats(rajiv, burgers).
eats(josie, Food).
% what Food does Josie eat? (2 answers)
eats(Person, curry).
% what Person eats curry? (2 answers)
eats(josie, Food), eats(Person, Food). % wholl share what with Josie?
Food=curry, Person=sam
600.325/425 Declarative Methods
- J. Eisner
10
eats(josie, Food).
% what Food does Josie eat? (2 answers)
eats(Person, curry).
% what Person eats curry? (2 answers)
eats(josie, Food), eats(Person, Food). % wholl share what with Josie?
Food=curry, Person=sam
600.325/425 Declarative Methods
- J. Eisner
11
Rules in Prolog
Lets augment our program with a new constraint:
eats(sam, dal).
eats(josie, samosas).
eats(sam, curry).
eats(josie, curry).
eats(rajiv, burgers).
eats(rajiv, dal).
compatible(Person1, Person2) :- eats(Person1, Food),
eats(Person2, Food).
head
body
12
Rules in Prolog
One way to satisfy the head of this rule is to satisfy the body.
why only one way? Why not if and only if?
allusion to movie Shallow Hal;
600.325/425
Declarative
Methods
shows
that constants
can appear in rules
- J. Eisner
13
14
15
eats(sam,Food), eats(Companion,Food).
Look familiar?
We get Companion=rajiv.
16
17
exit
redo
18
call
exit
call
19
redo fail
redo fail
20
call
fail
exit
redo
21
exit
redo
22
exit
redo
call
23
exit
redo
24
exit
redo
25
exit
redo
26
exit
redo
27
exit
redo
28
loves(hal, X)
call
fail
female(X)
rich(X)
exit
redo
29
Alternative rules
loves(hal, X) :- female(X), rich(X).
loves(Child, X) :- parent(X, Child).
loves(hal, X)
call
fail
female(X)
rich(X)
parent(X, hal)
exit
redo
exit
redo
30
Alternative rules
female(parvati).
female(josie).
female(martha).
female(X)
female(parvati)
female(josie)
female(martha)
loves(hal, X)
call
fail
female(X)
rich(X)
parent(X, hal)
exit
redo
exit
redo
31
Prolog as a database
language
The various eats(, ) facts can be regarded as rows in a
32
Recursive queries
boss(X,Y), married(X,Y).
above(X,X).
above(X,Y) :- boss(X,Underling), above(Underling,Y).
above(X,Y), married(X,Y).
33
Recursive queries
above(X,X).
above(X,Y) :- boss(X,Underling), above(Underling,Y).
above(c,h). % should return Yes
matches above(X,X)? no
boss(a,b). boss(a,c).
boss(b,d). boss(c,f).
boss(b,e).
a
b
d
c
e
f
g
34
Recursive queries
above(X,X).
above(X,Y) :- boss(X,Underling), above(Underling,Y).
above(c,h). % should return Yes
matches above(X,Y) with X=c, Y=h
boss(c,Underling),
matches boss(c,f) with Underling=f
above(f, h).
matches above(X,X)? no
boss(a,b). boss(a,c).
boss(b,d). boss(c,f).
boss(b,e).
a
b
d
c
e
f
g
35
Recursive queries
above(X,X).
above(X,Y) :- boss(X,Underling), above(Underling,Y).
above(c,h). % should return Yes
boss(a,b). boss(a,c).
matches above(X,Y) with X=c, Y=h
boss(b,d). boss(c,f).
boss(c,Underling),
boss(b,e).
a
matches boss(c,f) with Underling=f
above(f, h).
b
c
matches above(X,Y) with X=f, Y=h
(local copies of X,Y distinct from previous call) d e f
boss(f,Underling),
g h
36
Recursive queries
above(X,X).
above(X,Y) :- boss(X,Underling), above(Underling,Y).
above(c,h). % should return Yes
boss(a,b). boss(a,c).
matches above(X,Y) with X=c, Y=h
boss(b,d). boss(c,f).
boss(c,Underling),
boss(b,e).
a
matches boss(c,f) with Underling=f
above(f, h).
b
c
matches above(X,Y) with X=f, Y=h
(local copies of X,Y distinct from previous call) d e f
boss(f,Underling),
g h
37
38
1.
query
modes 2.
+,+
+,-,+
-,-
a
b
d
c
e
f
g
1. is better. Why?
2. is better. Why?
Doesnt matter much. Why?
39
1.
query
modes 2.
+,+
+,-,+
-,-
a
b
d
c
e
f
g
1. iteratesdoover
descendants of c, looking for e
1st-argument indexing.
2. iterates over ancestors of e, looking for c.
That makes
it much
to find
2. is better:
no node
has faster
very many
ancestors, but some
a given
children (boss(x,Y))
have a
lot ofxs
descendants.
If the
2. is better. Why?
If the query is above(X,e)?
If you dont like that, figure
outmatter
how to much. Why?
Doesnt
If the query is
above(X,Y)?
tell your Prolog to do 2nd-argument
indexing.
Or just
use subordinate(Y,X)
600.325/425
Declarative
Methods
- J. of
Eisner
instead
boss(X,Y)!
40
1.
2.
a
b
d
c
e
f
g
41
1.
2.
a
b
d
c
e
f
g
42
1.
2.
a
b
d
c
e
f
g
43
1.
2.
a
b
d
c
e
f
g
44
45
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B, date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
46
homepage(html(head(title("Peter A. Flach")),
body([img([align=right,src="logo.jpg"]),One big term
img([align=left,src="peter.jpg"]),representing
h1("Peter Flach's homepage"), an HTML web page.
The style on
h2("Research interests"),
the previous
ul([li("Learning from structured data"),
slide could get
...,
unmanageable.
li(a([href="CV.pdf"],"Full CV"))]),
h2("Current activities"),
...,
You have to
h2("Past activities"),
remember that
...,
birthday is
h2("Archives"),
argument #3
...,
pagetype(Webpage,researcher):of person, etc.
hr,address()
page_get_head(Webpage,Head),
])
head_get_title(Head, Title),
)).
This nondeterministic query asks
person(Title),
page_get_body(Webpage,Body),
body_get_heading(Body,Heading),
substring("Research",Heading).
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday( Stu , Bday) :- Stu=student(_, _, Bday).
date_get_year(Date,Year) :- Date=date(_, _, Year). bad style
student_get_bday(Student,Birthday),
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
Answer:
Student=student(456591, Fuzzy W, date(23, aug, 1966)),
Birthday=date(23, aug, 1966),
Year=1966.
600.325/425 Declarative Methods
- J. Eisner
48
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday(student(_, _, Bday),
date_get_year(date(_, _, Year), Year).
Bday)
.
good style
student_get_bday(Student,Birthday),
whoa, what are the
date_get_year(Birthday,Year),
variable bindings at
at_jhu(Student), Year < 1983.
this point??
Answer:
Student&Birthday
Student=student(456591, Fuzzy W, date(23,
aug, 1966)),
werent
forced to
Birthday=date(23, aug, 1966),
particular values
Year=1966.
by the constraint.
600.325/425 Declarative Methods
But were forced
49
- J. Eisner
into a relation
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday(student(_, _, Bday),
date_get_year(date(_, _, Year), Year).
Bday)
.
good style
student_get_bday(Student,Birthday),
student Student
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
? ?
?
Birthday
Answer:
Student=student(456591, Fuzzy W, date(23, aug, 1966)),
Birthday=date(23, aug, 1966),
Year=1966.
600.325/425 Declarative Methods
- J. Eisner
50
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday(student(_, _, Bday),
date_get_year(date(_, _, Year), Year).
Bday)
.
good style
student_get_bday(Student,Birthday),
student Student
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
? ? date
Birthday
Answer:
? 1966)),
?
?
Year
Student=student(456591, Fuzzy W, date(23, aug,
Birthday=date(23, aug, 1966),
Year=1966.
600.325/425 Declarative Methods
- J. Eisner
51
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday(student(_, _, Bday),
date_get_year(date(_, _, Year), Year).
Bday)
.
good style
student_get_bday(Student,Birthday),
student Student
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
128327 SK date
Birthday
Answer:
2 may
1986 Year
Student=student(456591, Fuzzy W, date(23, aug,
1966)),
Birthday=date(23, aug, 1966),
Year=1966.
600.325/425 Declarative Methods
- J. Eisner
52
Complex terms
at_jhu(student(128327, Spammy K', date(2, may, 1986))).
at_jhu(student(126547, Blobby B,
date(15, dec, 1985))).
at_jhu(student(456591, Fuzzy W',
date(23, aug, 1966))).
student_get_bday(student(_, _, Bday),
date_get_year(date(_, _, Year), Year).
Bday)
.
good style
Fail
student_get_bday(Student,Birthday),
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
(and backtrack)
Answer:
Student=student(456591, Fuzzy W, date(23, aug, 1966)),
Birthday=date(23, aug, 1966),
Year=1966.
600.325/425 Declarative Methods
- J. Eisner
53
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Anything). % variable in a fact
Query: eats(A, sundae(B,fudge)).
Answer: A=rajiv, B=mintchip
54
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Anything). % variable in a fact
Query: eats(A, sundae(B,fudge)).
What happens when we try to match this against facts?
eats
A
sundae
B
A=sam
fudge
eats
sam
dal
No match
sundaedal
(more precisely, sundae/2 dal/0)
55
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Anything). % variable in a fact
Query: eats(A, sundae(B,fudge)).
What happens when we try to match this against facts?
eats
A
sundae
B
A=josie
fudge
B=vanilla
eats
josie sundae
No match
vanilla caramel
fudgecaramel
56
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Anything). % variable in a fact
Query: eats(A, sundae(B,fudge)).
What happens when we try to match this against facts?
eats
A
sundae
B
A=rajiv
eats
rajiv
sundae
Match!
fudge
B=mintchip
mintchip fudge
57
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Anything). % variable in a fact
Query: eats(A, sundae(B,fudge))., icecream(B).
What happens when we try to match this against facts?
Match!
eats
eats
(B still unknown)
A=robot(C-3PO)
A
sundae
fudge
robot
Anything
Anything =
sundae(B,fudge)
C-3PO
58
eats(sam, dal).
eats(josie, sundae(vanilla, caramel)).
eats(rajiv, sundae(mintchip, fudge)).
eats(robot(C-3PO), Something) :- food(Something).
food(dal).
icecream(vanilla).
food(fudge).
icecream(chocolate).
food(sundae(Base, Topping)) :- icecream(Base),
food(Topping).
Query: eats(robot(A), sundae(B,fudge)).
Answer: A=C-3PO, B can be any kind of ice cream
600.325/425 Declarative Methods
- J. Eisner
59
foo
bar
blah
f
blah
bar
2
D
This is like unit propagation in DPLL SAT solvers.
61
62
unification
Lets use the = constraint to invoke unification directly
foo
bar
?
B
blah
blah 2
f
?
bar
?
foo
A
blah
blah 2
bar
f
?
63
unification
The = constraint invokes unification directly
bar
?
B
foo
blah
blah 2
f
?
bar
?
foo
A
blah
blah 2
bar
f
?
64
unification
The = constraint invokes unification directly
bar
?
B
foo
blah
blah 2
f
?
bar
?
foo
A
blah
blah 2
bar
f
?
65
unification
The = constraint invokes unification directly
bar
?
B
foo
blah
blah 2
f
?
bar
?
foo
A
blah
blah 2
bar
f
?
66
67
Variable bindings that arise during a unification may affect Prologs ability
to complete the unification, or to do subsequent unifications that are
needed to satisfy additional constraints (e.g., those from clause body).
1.
equal(X,X).
equal(foo(A,3), foo(2,B)).
69
equal
foo
A
equal
foo
3 2
foo
70
student_get_bday(Student,Birthday),
student_get_bday
Student
Birthday
?
?
student_get_bday
student
?
Bday
71
student_get_bday(Student,Birthday),
student_get_bday
Student
student
Birthday
? ? ?
600.325/425 Declarative Methods
- J. Eisner
72
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
student_get_bday date_get_year
Student
Year
student
?
Birthday
? ? ?
600.325/425 Declarative Methods
- J. Eisner
date_get_year
date
?
Yr
73
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
student_get_bday date_get_year
Student
student
Birthday
? ? date
Year
? ? ?
600.325/425 Declarative Methods
- J. Eisner
74
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
Note: We dont really care
student_get_bday date_get_year
about the black pieces anymore.
Student
They are just left-over junk
student
that helped us satisfy previous
Birthday
constraints. We could even
? ? date
garbage-collect them now, since
Year
no variables point to them.
? ? ?
Declarative
The rest of the structure600.325/425
is exactly
what Methods
we hoped for (earlier slide).
- J. Eisner
75
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
at_jhu(Student),
at_jhu
at_jhu
student_get_bday date_get_year
Student
student
student
Birthday
? ? date
128327 SK date
Year
2 may 1986
? ? ?
76
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
at_jhu(Student),
at_jhu
student_get_bday date_get_year
Student
student
Birthday
128327 SK date
Year
2 may 1986
77
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
at_jhu
student_get_bday date_get_year
Student
fail! 1986 < 1983
student
Birthday
doesnt match anything
128327 SK date
<
in database. (Well, okay,
Year
actually < is built-in.)
1983
2 may 1986
78
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
at_jhu(Student),
at_jhu
at_jhu
student_get_bday date_get_year
backtrack!
Student
student
student
Birthday
? ? date
128327 SK date
Year
2 may 1986
? ? ?
79
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
at_jhu(Student),
at_jhu
at_jhu
student_get_bday date_get_year
try another
Student
student
student
Birthday
? ? date
126547 BB date
Year
15 dec 1985
? ? ?
80
unification
Lets use the = constraint to invoke unification directly
foo
bar
?
B
blah
blah 2
f
?
bar
?
foo
A
blah
blah 2
bar
f
?
81
unification
The = constraint invokes unification directly
foo
bar
?
B
blah
blah 2
f
?
bar
foo
A
blah
blah 2
bar
?
Each ? stores a pointer.
D
Initially its the null pointer, but when ? is first unified with another term,
change it to point to that term. (This is whats undone upon backtracking.)
Future accesses to the ? dont see the ?; they transparently follow its pointer.
(If two ?s with null pointers 600.325/425
are unified,
pick one
and make it point to the other
Declarative
Methods
J. Eisner
(just as in the Union-Find algorithm). -This
may lead to chains of pointers.) 82
83
male(terah).
male(abraham). male(nahor).
male(haran).
male(isaac).
male(ismael).
male(uz).
male(kemuel). male(bethuel).
male(lot).
male(iscah).
male(esau).
male(jacob).
male(massa).
male(hadad). male(laban).
male(reuel).
male(levi3rd).
male(judah4th).
male(aliah). male(elak).
male(moab). male(benammi).
84
mother(terahs_second_wife, sarah).
mother(terahs_first_wife, abraham).
mother(terahs_first_wife, nahor).
mother(terahs_first_wife, haran).
mother(sarah, isaac).
mother(hagar_concubine, ismael).
mother(milcah, uz).
mother(milcah, kemuel).
mother(milcah, bethuel).
mother(harans_wife, milcha).
mother(harans_wife, lot).
mother(harans_wife, iscah).
mother(rebekah, esau).
mother(rebekah, jacob).
mother(ismaels_wife, massa).
mother(ismaels_wife, mahalath).
mother(ismaels_wife, hadad).
mother(ismaels_wife, bashemath).
mother(bethuels_wife, laban).
mother(bethuels_wife, rebekah).
mother(lots_first_wife, first_daughter).
mother(lots_first_wife, second_daughter).
mother(first_daughter, moab).
mother(second_daughter, ben_ammi).
mother(bashemath, reuel).
mother(leah, levi3rd).
mother(leah, judas4th).
mother(mahalath, aliah).
mother(mahalath, elak).
mother(lebans_wife,
rachel).
600.325/425 Declarative
Methods
mother(lebans_wife, leah).
- J. Eisner
85
86
mother(sarah,isaac).
father(abraham,isaac).
87
female(sarah).
male(abraham).
parent(sarah, isaac).
parent(abraham, isaac).
anc(0,X,X).
anc(N,X,Y) :- parent(X,Z), anc(N-1,Z,Y).
parent(X,Y)
:- anc(1,X,Y).
mother(X,Y)
:- parent(X,Y), female(X).
father(X,Y)
:- parent(X,Y), male(X).
grandparent(X,Y) :- anc(2,X,Y).
grandmother(X,Y) :- grandparent(X,Y), female(X).
grandfather(X,Y) :- grandparent(X,Y), male(X).
great_grandparent(X,Y) :- anc(3,X,Y).
etc.
600.325/425 Declarative Methods
- J. Eisner
88
anc(0,X,X).
anc(N,X,Y) :- parent(X,Z), anc(N-1,Z,Y).
89
anc(0,X,X).
anc(N,X,Y) :- parent(X,Z), anc(N-1,Z,Y).
90
anc(0,X,X).
anc(N,X,Y) :- parent(X,Z), anc(N-1,Z,Y).
N > 0, M is N-1, parent(X,Z), anc(M,Z,Y).
is does arithmetic for you:
is(0,1-1).
0 is 1-1.
is(4,2+2).
4 is 2+2.
is(24, 7*7-5*5)
24 is 7*7-5*5.
91
anc(0,X,X).
anc(N,X,Y) :- M is N-1, parent(X,Z), anc(M,Z,Y).
Same problem if we have the constraint N > 0, which only allows >(+,+).
Here the ECLiPSe delayed constraint would be N #> 0.
600.325/425 Declarative Methods
- J. Eisner
92
anc(0,X,X).
anc(N,X,Y) :- M is N-1, M >= 0, parent(X,Z), anc(M,Z,Y).
anc(0,X,X).
anc(N,X,Y) :- parent(X,Z), anc(M,Z,Y), N is M+1.
Here we query parent(+,-), which binds Z,
and then recursively query anc(-,+,+) again, which binds M,
and then query is(-,+), which is a permitted mode for is. That works.
93
are
deepcousin(X,Y):- sibling(X,Y).
94
Ancestry
deepcousin(X,Y):- sibling(X,Y).
95
Lists
cons(3,cons(4,nil)) cons(1,cons(2,X))
96
Lists
[1,2,3,4]=[1,2|X] X=[3,4]
cons(1,cons(2,X))
by unification
cons(3,cons(4,nil))
97
Lists
[1,2]
=[1,2|X]
cons(1,cons(2,X))
X=[]
nil
98
Decomposing lists
first(X,List) :- ?
first(X,List) :- List=[X|Xs].
first(X, [X|Xs]).
first(X, [X|_]).
99
Decomposing lists
first(X, [X|_]).
rest(Xs, [_|Xs]).
Answer: no
Answer: X=7
Answer: List=[7|Xs]
(will probably print an internal var name like _G123 instead of Xs)
Answer: List=[7,8,9].
Can you draw the structures that get unified to do this?
600.325/425 Declarative Methods
- J. Eisner
100
Decomposing lists
101
102
Answer:
X=8 ;
X=7
X=7 ;
103
104
How do
Query:
length(List,
3), member(7, List), member(8,List).
we define length?
length([], List=[7,
0).
Answer:
8, X] ;
length([_|Xs],N) :- N > 0,
List=[7, X, 8] ;
length(Xs,M),
N is
List=[X, 7, 8]
; M+1.
But this will cause an
List=[8, 7, X] ;
instantiation fault when we
List=[8, X, 7] ;
recurse. Well try to test
MList=[X,
> 0, but 8,
M 7]
is still unbound.
105
106
.
length(Xs,M),
M
is
N+1.
length([_|Xs],N) :List=[X, 7, 8] ;
The problem:
But this will cause an
length(Xs,M), N is M+1.
List=[8, 7, X] ;
instantiation
fault
when we But this will cause infinite
N is M+1
is not pure
List=[8,
X, 7]
; Prolog.
and
try to test M >
Neitherrecurse
is
N
>
0.
recursion for length(List,3).
List=[X,
8,
7]
M is still unbound.
These 0.
constraints cant be processed by unification
108
length([ ],z).
length([_|Xs], s(N)) :- length(Xs,N).
This is pure Prolog and will work perfectly everywhere.
Yeah, its a bit annoying to use Peano integers for input/output:
yuck?
109
length([ ],z).
length([_|Xs], s(N)) :- length(Xs,N).
This is pure Prolog and will work perfectly everywhere.
Converting between Peano integers and ordinary numbers:
110
111
112
add(
original query
113
add
note the
unification
of variables
between
different calls
original query
matches head of rule
114
115
add(z,B,B).
% 0+B=B.
A+B=S.
add
z
original query
matches head of rule
add(z,B,B).
% 0+B=B.
add(s(A),B,s(Sum)) :- add(A,B,Sum). % (A+1)+B=(S+1)
A+B=S.
117
An amusing query
118
append(Xs,Ys):
if (Xs.empty())
return Ys
else
subproblem = Xs.rest(); // all but the 1st element
subsolution = append(subproblem, Ys)
return cons(Xs.first(), subsolution)
600.325/425 Declarative Methods
- J. Eisner
119
append([],Ys): return Ys
append([X|Xs],Ys): return [X | append(Xs,Ys)]
120
In actual Prolog, the function looks much the same, but once
youve written it, you can also run it backwards!
In Prolog there are no return values. Rather, the return value
is a third argument: append(Xs,Ys,Result).
This is a constraint saying that Result must be the append of
the other lists.
Any of the three arguments may be known (or partly known)
at runtime. We look for satisfying assignments to the others.
121
Try this:
append([],Ys,Ys).
append([X|Xs],Ys,Result) :- ?
122
Try this:
append([],Ys,Ys).
append([X|Xs],Ys,Result) :- append(Xs,[X|Ys],Result).
123
appendrev([],Ys,Ys).
appendrev([X|Xs],Ys,Result) :- appendrev(Xs,[X|Ys],Result).
124
Query: append([1,2],[3,4],Result)
Answer: Result=[1,2,3,4]
append([],Ys,Ys).
append([X|Xs],Ys,[X|Result]) :- append(Xs,Ys,Result).
1. our
inputs
4. construct
our output
2. inputs to
recursive call
3. output of
recursive call
125
Query: append([1,2],[3,4],Result)
Answer: Result=[1,2,3,4]
append([],Ys,Ys).
append([X|Xs],Ys,[X|Result]) :- append(Xs,Ys,Result).
This version also makes perfect sense declaratively.
And we still have a use for the other version, appendrev:
appendrev(Xs,[],Ys).
reverse(Xs,Ys) :- ?
600.325/425 Declarative Methods
- J. Eisner
126
Arithmetic continued:
Subtraction
add(z,B,B).
% 0+B=B.
add(z,B,B).
% 0+B=B.
add(s(A),B,s(Sum)) :- add(A,B,Sum). % (A+1)+B=(S+1)
A+B=S.
add(s(s(z)), X, s(s(s(s(s(z)))))).
add(s(s(s(s(s(z))))), X, s(s(z))).
127
128
Square roots
mult(X, X, s(s(s(s(s(s(s(s(s(z)))))))))).
129
sort(Xs, Ys)
130
ordered([]).
ordered([X]).
ordered([X,Y|Ys]) :- ?
131
ordered([]).
ordered([X]).
ordered([X,Y|Ys]) :- X =< Y, ordered([Y|Ys]).
132
133
134
Mergesort
Query: mergesort([4,3,6,5,9,1,7],S).
Answer: S=[1,3,4,5,6,7,9]
mergesort([],[]).
mergesort([A],[A]).
mergesort([A,B|R],S) :split([A,B|R],L1,L2),
mergesort(L1,S1), mergesort(L2,S2),
merge(S1,S2,S).
split([],[],[]).
split([A],[A],[]).
split([A,B|R],[A|Ra],[B|Rb]) :- split(R,Ra,Rb).
merge(A,[],A).
merge([],B,B).
merge([A|Ra],[B|Rb],[A|M]) :- A =< B, merge(Ra,[B|Rb],M).
merge([A|Ra],[B|Rb],[B|M]) :- A > B, merge([A|Ra],Rb,M).
600.325/425 Declarative Methods
- J. Eisner
135
for A {0, 1}
for B {0, 1}
for C {0, 1}
for D {0, 1}
for E {0, 1}
if formula is true
immediately return (A,B,C,D,E)
return UNSAT
136
bool(A),bool(B),bool(C),bool(D),bool(E),formula(A,B,C,D,E).
Program
137
bool(A),bool(B),bool(C),bool(D),bool(E),formula(A,B,C,D,E).
Program
A
B
C
D
E
false
false
false
true
true
false
true
false
true false
true
true
false
true
138
Query
bool(A),bool(B), , bool(C),bool(D),bool(E),formula(A,B,C,D,E).
Program
false
false
false
true
139
Query
bool(A),bool(B),bool(C),bool(D),bool(E),formula(A,B,C,D,E), .
Program
false
false
false
true
true
false
true
false
true false
140
Query
bool(A),bool(B),bool(C), ,bool(D),bool(E),formula(A,B,C,D,E).
Program
A
B
C
D
E
false
false
false
141
Query
bool(A), bool2(B,C),
!,bool(D),bool(E),formula(A,B,C,D,E).
Program
false
false
false
142
Query
bool(A), bool2(B,C),
,bool(D),bool(E),formula(A,B,C,D,E).
Program
Now effect of !
% values available for backtracking searchis local to bool2.
bool2 will commit to
bool(false). bool(true).
its first solution,
bool2(X,Y) :- bool(X), bool(Y), .
namely (false,false),
% equivalent to: bool2(false,false).
not backtracking to
get other solutions.
false
true
A
But thats just how
false
false
B
bool2 works inside.
false
false
C
Red query doesnt
D
know bool2 contains a
E
cut; it backtracks to
try different A,
600.325/425 Declarative Methods
calling bool2 for143each.
- J. Eisner
call
fail
exit
redo
subroutine
for
clause #2
Can try other
options here
before failing
and returning
to caller
Normal backtracking
if we fail
within clause #2
144
Query
bool(A),bool(B),bool(C),bool(D),bool(E),formula(A,B,C,D,E).
Program
145
Query
bool(A),bool(B),bool(C),bool(D),bool(E),formula(A,B,C,D,E).
Program
Another pedagogical
eats(sam, dal).
eats(josie, samosas).
example
of
cut
eats(sam, curry).
eats(josie, curry).
eats(rajiv, burgers).
eats(rajiv, dal).
compatible(Person1, Person2) :- eats(Person1, Food),
eats(Person2, Food).
compatible(Person1, Person2) :- watches(Person1, Movie),
watches(Person2, Movie).
To whom should we advertise curry?
eats(X,curry), compatible(X,Y).
eats(X,curry), !, compatible(X,Y).
eats(X,curry), compatible(X,Y), !.
X=sam, Y=sam
600.325/425 Declarative Methods
- J. Eisner
147
148
149
150
Yes
\+ eats(sam,X).
No
\+ eats(sam,rutabaga).
eats(rajiv, dal).
No
\+ eats(robot,X).
Yes
151
avoids(sam,rutabaga).
Yes
avoids(sam,X).
No
No
avoids(robot,X).
Yes
152
Answer: Ys=[1,3,1]
deleteall(X,[X|Xs],Ys) :- deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- Z\=X, deleteall(Z,Xs,Ys).
Works fine for ground terms :
deleteall(Z,[],[]).
2 \= 1, so we dont delete 1.
153
deleteall(X,[X|Xs],Ys) :- deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- Z\=X, deleteall(Z,Xs,Ys).
deleteall(Z,[],[]).
Wed like \= to mean constrained not to unify.
154
deleteall(X,[X|Xs],Ys) :- ! , deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- deleteall(Z,Xs,Ys).
deleteall(Z,[],[]).
155
156
157
159
Constraint logic
programming
In constraint logic programming,
you can include constraints on integers
like N #= M+1 (rather than N is M+1) and X#\=Z (rather than X \=Z)
160
Constraint logic
programming
X #= 2*Y, X=10.
X #> 2*Y, X=10.
member(X,[1,2,3,4,2]), X #= 2*Y.
X #= 2*Y, member(X,[1,2,3,4,2]).
uniqmember
simplified version of Golomb ruler (from Eclipse website)
600.325/425 Declarative Methods
- J. Eisner
161
Wrong answer:
alldiff([]).
alldiff([X|Xs]) :- member(Y,Xs), X #\= Y, alldiff(Xs).
alldiff([]).
? (see homework)
600.325/425 Declarative Methods
- J. Eisner
162