The Department of Computer Science & Engineering
|
|
STUART C. SHAPIRO: CSE
305
|
Logic programming is also called relational programming, as opposed to functional programming.
Mathematical facts:
append that
takes two lists and returns a list containing all the members of the
first list followed by all the members of the second list.
append is predefined in Common Lisp, but could be written
as:
Notice thattest(10): (defun append (list1 list2) (if (endp list1) list2 (cons (first list1) (append (rest list1) list2)))) append test(11): (append '(a b c) '(d e f)) (a b c d e f)
append is a function of the form
f(x1, x2) = y, where if x1 = (a b c)
and x2 = (d e f), then y = (a b c d e f).
The prolog version of append is a three-argument
relation, append(X, Y, Z) which is true if Z
is a list whose members are the members of X followed by
the members of Y.
Note:
And here is an interactive test of that program:append([], List2, List2). append([First | Rest], List2, [First | Intermediate]) :- append(Rest, List2, Intermediate).
<cirrus:Programs:1:103> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
% consulted /u0/faculty/shapiro/CSE305/Programs/append.prolog in module user, 0 msec 392 bytes
yes
| ?- append([a, b, c], [d, e, f], X).
X = [a,b,c,d,e,f] ?
yes
| ?- halt.
Interestingly, Prolog does not distinguish in parameters from out
parameters. (They are all inout parameters.) It depends on which of
the actual parameters are constants and which are variables. Here is
another test of the append program:
<cirrus:Programs:1:104> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
% consulted /u0/faculty/shapiro/CSE305/Programs/append.prolog in module user, 0 msec 392 bytes
yes
| ?- append([a, b, c], [d, e, f], X).
X = [a,b,c,d,e,f] ?
yes
| ?- append(X, [d, e, f], [a, b, c, d, e, f]).
X = [a,b,c] ?
yes
| ?- append([a, b, c], X, [a, b, c, d, e, f]).
X = [d,e,f] ?
yes
| ?- halt.
The top-level syntax of a Prolog program is
<program> -> {<clause>}You interact with Prolog by loading a program (by "consulting" a file), and then typing a query to the interactive system.
<clause> -> <fact> | <rule> | ?- <query>
<fact> -> <head>.
<rule> -> <head> :- <body> .
<query> -> <body>.
<head> -> <relation>
<body> -> [<relation> {, <relation>}]
<relation> -> <predicate> [( <term> {, <term})]
A <fact> is a relation that holds.
A <rule> says that the <head> holds if every <relation> in its <body> holds.
The set of <clause>s having the same <predicate> in their <head> constitutes a procedure for that <predicate>.
The scope of a variable is a single <clause> or <query>.
append was designed to compute the value of one actual
argument when the other two were supplied. member is a
two-argument relation designed to say whether its first argument is a
member of the list which is its second argument. It is comparable to
the Lisp member function:
Here is a first version oftest(15): (defun member (obj list) (cond ((endp list) nil) ((eql obj (first list)) t) (t (member obj (rest list))))) member test(16): (member 'b '(a b c)) t test(17): (member 'z '(a b c)) nil
member in Prolog:
member(Obj, [Obj | Rest]).
member(Obj, [First | Rest]) :- member(Obj, Rest).
------------------------------------------
<cirrus:Programs:1:106> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
* [Rest] - singleton variables in user:member/2
* Approximate lines: 1-2, file: '/u0/faculty/shapiro/CSE305/Programs/member.prolog'
* [First] - singleton variables in user:member/2
* Approximate lines: 2-3, file: '/u0/faculty/shapiro/CSE305/Programs/member.prolog'
% consulted /u0/faculty/shapiro/CSE305/Programs/member.prolog in module user, 0 msec 352 bytes
yes
| ?- halt.
The complaint is to a variable that appears in the head, but not in
the body of a rule. Such a variable may appear as an "anonymous
variable", written as _. No "anonymous variable" is the
same as any other variable.
Here's the final version of member with some tests:
member(Obj, [Obj | _]).
member(Obj, [_ | Rest]) :- member(Obj, Rest).
-----------------------------------------------
<cirrus:Programs:1:107> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
% consulted /u0/faculty/shapiro/CSE305/Programs/member.prolog in module user, 0 msec 328 bytes
yes
| ?- member(b, [a, b, c]).
yes
| ?- member(z, [a, b, c]).
no
| ?- halt.
The clauses in a procedure are tried in order, from the first to the last in the program, until one succeeds, thus constituting a multi-branch selection.
If the query contains a variable, then there may be multiple ways
the program may succeed. The first way is shown, and the user may
terminate the query by entering a CR, or may have the program find
another way to succeed by entering ;. If the user keeps
doing this, the program will ultimately fail (when there are no more
ways to succeed):
<cirrus:Programs:1:108> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
% consulted /u0/faculty/shapiro/CSE305/Programs/member.prolog in module user, 0 msec 328 bytes
yes
| ?- member(X, [a, b, c]).
X = a ? ;
X = b ? ;
X = c ? ;
no
| ?- halt.
append([], List2, List2).
append([First | Rest], List2, [First | Intermediate]) :-
append(Rest, List2, Intermediate).
------------------------------------------------------------
<cirrus:Programs:1:127> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
Licensed to cse.buffalo.edu
| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
% consulted /u0/faculty/shapiro/CSE305/Programs/append.prolog in module user, 0 msec 392 bytes
yes
| ?- append([X, b, [c], d], [e, X , Y], [a, b, [Y] | Z]).
X = a,
Y = c,
Z = [d,e,a,c] ?
yes
This figure shows the matching variables, and how information flows to
instantiate them:
is. Note the difference between
= and is.
| ?- X = 3. X = 3 ? yes | ?- 3 = X. X = 3 ? yes | ?- X is 3. X = 3 ? yes | ?- 3 is X. ! Instantiation error in argument 2 of is/2 ! goal: _73 is _74 | ?- X = 3 + 5. X = 3+5 ? yes | ?- 3 + 5 = X. X = 3+5 ? yes | ?- X is 3 + 5. X = 8 ? yes | ?- 3 + 5 is X. ! Instantiation error in argument 2 of is/2 ! goal: _73 is _74
This version differs from the original in that it ends with a query
that begins execution of the program. (Compare the automatic start of
main in the C-based languages.
echo :- format("~nType something to each prompt.~n\c
Do not start with a capital letter.~n\c
End every input with a period.~n\c
Type bye to quit.~2n", []),
prompt_and_read(1).
prompt_and_read(N) :-
format("~d: ", [N]),
read(X),
echo_and_loop(N, X).
echo_and_loop(_, bye):- format("Good bye.~n", []), halt.
echo_and_loop(N, X) :-
format("I read -->~a<--~n", [X]),
N1 is N + 1,
prompt_and_read(N1).
?- echo.
-----------------------------------------------------------
<cirrus:Programs:1:129> sicstus -l echo.prolog
% compiling /u0/faculty/shapiro/CSE305/Programs/echo.prolog...
Type something to each prompt.
Do not start with a capital letter.
End every input with a period.
Type bye to quit.
1: 'Hello there'.
I read -->Hello there<--
2: hi.
I read -->hi<--
3: bye.
Good bye.
% compiled /u0/faculty/shapiro/CSE305/Programs/echo.prolog in module user, 40 msec 6056 bytes
For another example, here's the factorial program in Prolog:
And here's factorial tutorial on the web, complete with an animated evaluation.factorial(0, 1). factorial(N, F) :- N > 0, Prev is N-1, factorial(Prev, M), F is N * M.