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).
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: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.
The top-level syntax of a Prolog program is<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.
<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:
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 asmember(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.
_
. 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.
This figure shows the matching variables, and how information flows to instantiate them: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
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.
For another example, here's the factorial program in Prolog: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
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.