Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programming in Logic
“One way to satisfy the head of this rule is to satisfy the body.”
why only “one way”? Why not “if and only if”?
shows that constants can appear in rules
600.325/425 Declarative Methods - J. Eisne 13
r
The Prolog solver
Prolog’s solver is incredibly simple.
eats(sam,X).
Iterates in order through the program’s “eats” clauses.
First one to match is eats(sam,dal).
so it returns with X=dal.
If you hit semicolon, it backtracks and continues:
Next match is eats(sam,curry).
so it returns with X=curry.
call exit
fail redo
call exit
fail redo
call exit
fail redo
call exit
fail redo
call exit
fail redo
call exit
fail redo
call exit
redo fail redo
loves(sam, X)
call exit
female(X) rich(X)
fail redo
loves(sam, X)
call exit
female(X) rich(X)
redo
exit
parent(X, sam) redo
fail
loves(sam, X)
call exit
female(X) rich(X)
redo
exit
parent(X, sam) redo
fail
b c
d e f
g h
g h
Fail
student_get_bday(Student,Birthday),
date_get_year(Birthday,Year),
at_jhu(Student), Year < 1983.
Answer: (and backtrack)
Student=student(456591, ‘Fuzzy W’, date(23, aug, 1966)),
Birthday=date(23, aug, 1966),
Year=1966.
B fudge sundaedal
(more precisely, sundae/2 dal/0)
foo foo
B f blah 2 E
foo foo
foo foo
foo foo
2 3
If we wanted to call it = instead of equal, A B
we could write ’=’(X,X) as our program
fact. Prolog even lets you declare ’=’ as
infix, making X=X a synonym for ’=’(X,X).
student_get_bday(Student,Birthday),
student_get_bday student_get_bday
Student Birthday
? ? student
? ? ? Bday
student_get_bday(Student,Birthday),
student_get_bday
Student
student
Birthday
? ? ?
student_get_bday(Student,Birthday), date_get_year(Birthday,Year),
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. Eisne 74
r
Now we should really get the birthday
example
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,Birthday), date_get_year(Birthday,Year),
at_jhu at_jhu
student_get_bday date_get_year
Student
student student
Birthday
? ? date 128327 SK date
Year
? ? ? 2 may 1986
600.325/425 Declarative Methods - J. Eisne 76
r
Now we should really get the birthday
example
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))).
at_jhu
student_get_bday date_get_year
Student
student
Birthday
128327 SK date
Year
2 may 1986
600.325/425 Declarative Methods - J. Eisne 77
r
Now we should really get the birthday
example
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))).
at_jhu
student_get_bday date_get_year
Student
student fail! 1986 < 1983
Birthday doesn’t match anything
128327 SK date < in database. (Well, okay,
Year actually < is built-in.)
2 may 1986 1983
600.325/425 Declarative Methods - J. Eisne 78
r
Now we should really get the birthday
example
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))).
at_jhu at_jhu
student_get_bday date_get_year backtrack!
Student
student student
Birthday
? ? date 128327 SK date
Year
? ? ? 2 may 1986
600.325/425 Declarative Methods - J. Eisne 79
r
Now we should really get the birthday
example
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))).
at_jhu at_jhu
student_get_bday date_get_year try another
Student
student student
Birthday
? ? date 126547 BB date
Year
? ? ? 15 dec 1985
600.325/425 Declarative Methods - J. Eisne 80
r
Time to try some programming!
nth_cousin(N,X,Y) :- …?
What is the base case?
Who are my 3rd cousins?
For what N are we Nth cousins?
cons(3,cons(4,nil)) cons(1,cons(2,X))
cons(1,cons(2,X)) cons(3,cons(4,nil))
cons(1,cons(2,X)) nil
first(X,List) :- List=[X|Xs].
Traditional variable name:
“X followed by some more X’s.”
first(X, [X|Xs]).
Nicer: eliminates the single-use variable List.
first(X, [X|_]).
Also eliminate the single-use variable Xs.
z z ? original query
matches head of rule
z z
? 1st recursive call
matches head of rule
z z
? 2nd recursive call
matches base case
Removed outer skins from 1st argument (outside-in),
nested them to form the result (outside-in),
dropped 2600.325/425
r
nd
argument
Declarative into
Methodsthe core.
- J. Eisne 109
More 2+2: An interesting variant
First, let’s define a predicate add/3.
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.
Query: add(s(s(z)), s(s(z)), Total ). % 2+2=?
Matches head of second clause: A=s(z), B=s(s(z)), Total=s(Sum).
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)
In actual Prolog, the function looks much the same, but once
you’ve 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.
Try this:
append([],Ys,Ys).
append([X|Xs],Ys,Result) :- … ?
Try this:
append([],Ys,Ys).
append([X|Xs],Ys,Result) :- append(Xs,[X|Ys],Result).
But wait: what order are the onion skins being
wrapped in?
This is like the first version of 2+2 …
Query: append([1,2],[3,4],Result)
Answer: Result=[1,2,3,4]
Query: append([1,2],[3,4],Result)
Answer: Result=[1,2,3,4]
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))).
mult(X, X, s(s(s(s(s(s(s(s(s(z)))))))))).
ordered([]).
ordered([X]).
ordered([X,Y|Ys]) :- … ?
ordered([]).
ordered([X]).
ordered([X,Y|Ys]) :- X < Y, ordered([Y|Ys]).
deleteone(X,[X|Xs],Xs).
deleteone(Z,[X|Xs],[X|Ys]) :-
deleteone(Z,Xs,Ys).
deleteall(X,[X|Xs],Ys) :- deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- X\=Z,
deleteall(Z,Xs,Ys).
deleteall(X,[X|Xs],Ys) :- !, deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- deleteall(Z,Xs,Ys).
Wait, we’re missing one more clause:
deleteall(_,[],[]).
deleteall(X,[X|Xs],Ys) :- !, deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- deleteall(Z,Xs,Ys).
Wait, we’re missing one more clause:
deleteall(_,[],[]).
deleteall(X,[X|Xs],Ys) :- !, deleteall(X,Xs,Ys).
deleteall(Z,[X|Xs],[X|Ys]) :- deleteall(Z,Xs,Ys).
Wait, we’re missing one more clause:
deleteall(_,[],[]).
main routine
subroutine
for
clause #2
We did on blackboard:
a couple of small examples of CLP
how to write alldiff using CLP
an incorrect version of alldiff, using “member”
(incorrect because “member” backtracks and
erases constraints) – see hw
Golomb ruler (from Eclipse website)
Wrong answer:
alldiff([]).
alldiff([X|Xs]) :- member(Y,Xs), X #\= Y, alldiff(Xs).
Right answer (although no strong propagator):
alldiff([]).
…