Lecture 13

Today:

    1. Quiz.

    2. Reading questions.

    3. Homework 7.

For next time:

    1. Finish Homework 7.

    2. Prolog exercises below.

More Prolog

declarative reading vs. operational reading

Declarative means that you read what the rules mean; operational means you think about how Prolog actually executes.

Here's a (modified) example from Programming in Prolog, by Clocksin and Mellish. (With apologies for the heterosexism of this example.)

boy(harry).

boy(ron).

boy(neville).

boy(draco).

girl(hermione).

girl(ginny).

girl(fleur).

pair(X,Y) :- boy(X), girl(Y).

What's the declarative reading of pair?

"X,Y is a pair if X is a boy and Y is a girl."

What's the operational reading; that is, what's going to happen when we ask pair(X,Y)?

    1. Search for a X that makes boy(X) true.

    2. Search for a Y that makes girl(Y) true.

    3. Report a pair.

    4. Backtrack and see if there's another Y that makes girl(Y) true.

    5. When you run out of Ys, backtrack and start enumerating Xs.

    6. When you run out of Xs, stop.

How to run Prolog in your head:

1) For a given predicate, start with the first rule/fact and work your way down.

2) Try to satisfy the first clause.

a) If you find a match, instantiate one or more variables, and move on to the next clause.

b) If the clause fails (doesn't find a match), backtrack to the previous clause and try to re-satisfy the goal.

The cut

The cut is a special predicate, spelled !, that

1) succeeds immediately and moves on to the next clause, but

2) if you backtrack and hit a cut, it fails immediately and

does _not_ try to resatisfy the previous goal.

What effect does this have on the previous example:

pair(X,Y) :- boy(X), !, girl(Y).

What about

pair(X,Y) :- !, boy(X), girl(Y).

What about

pair(X,Y) :- boy(X), girl(Y), !.

A common use of cut is the cut-fail combination, which means "if you get this far, you lose".

pair(X,Y) :- boy(X), girl(Y), !, fail.

not

Which suggests an implementation of one version of not:

not(P) :- call(P), !, fail.

not(P).

call(P) means "try to satisfy P"

What happens if it succeeds? What happens if it fails?

Notice that not(girl(X)) does not enumerate all instantiations of X for which girl(X) is false, which is what you might have meant/wanted.

How would you do that?

Lists

Prolog provides lists as a basic type, with the usual syntax:

[1, 2, 3] is a list of three elements.

In a predicate, you can match the first element and the rest:

car([X|Y], X).

This means that the predicate car is true if the first argument is a list with X as the first element and Y as the rest, and if the second argument matches X.

Likewise with cdr and cons.

cdr([X|Y], Y).

cons(X, R, [X|R]).

member

You seldom use car and cdr explicitly. For example, here is an implementation of the built-in predicate member:

member(X,[X|R]).

member(X,[Y|R]) :- member(X,R).

This checks membership (obviously):

| ?- member(3, [1,2,3]).

true

But it also enumerates the members:

yes

| ?- member(X, [1,2,3]).

X = 1

X = 2

X = 3

And even generates all the lists that contain a given element!

| ?- member(1, X).

X = [1|_] ? ;

X = [_,1|_] ? ;

X = [_,_,1|_] ? ;

X = [_,_,_,1|_] ?

and so on...

Write a set of rules that define a predicate cross/3 that takes list A and B, and a pair P, and unifies if P is a member of the Cartesian product of A and B.

Takeout

Type in these rules:

takeout(X,[X|R],R).

takeout(X,[F|R],[F|S]) :- takeout(X,R,S).

And try these examples:

1) takeout(2,[1,2,3],L).

2) takeout(X,[1,2,3],L).

3) takeout(3, W, [a,b,c]).

What's a better name for "takeout" in example 3?

Append

Here's a definition of myappend (append is a built-in predicate):

myappend([],X,X).

myappend([X|R],Y,[X|S]) :- myappend(R,Y,S).

Try these examples:

1) myappend([1,2,3],[4,5],A).

2) myappend([1,2,3],W,[1,2,3,4,5]).

3) myappend(A,[5],[1,2,3,4,5]).

4) myappend(X, Y, [1,2,3,4,5]).

Can you write a definition for myreverse? Hint: think about the tail-recursive version of reverse we did in Racket, then write a 3-argument version of myreverse so that

myreverse([1,2,3], [], [3,2,1])

and

myreverse([2,3], [1], [3,2,1])

are true.