Prolog 2

How Does Prolog Work?

Unification

Unification Algorithm

Unification Example

The Goal Stack

Choice Points

Variable Renaming

Summary of Prolog Algorithm

Numbers in Prolog

Lab

???

Step 1: Unification

  1. Consider the terms
    member(X, cons(john, cons(mary, nil)))
    member(X17, cons(X17, T))

    Compute a unifying substitution (by hand). What is it?

  2. Consider the goal
    member(X, cons(john, cons(mary, nil)))

    and the clause

    member(X, cons(X, T)) :- member(X,T).

    Compute a unifying substitution of the goal and the head of the clause after renaming variables in the clause. What is it?

  3. Apply the substitution to the body of the clause. What term do you get?

Step 2: How Prolog Works

Save this Prolog.scala file. In a shell window, type

scala -i Prolog.scala

When you get a prompt, type these commands:

import Prolog._
val member = new Predicate
member('X, 'X::'Xs)!
member('X, 'Y::'Ys) :- member('X, 'Ys)
member('X, 'john :: 'mary :: 'nil)?
more
more

As you can see, the implementor of this interpreter cleverly overloaded operators ! (fact), :- (provided that) and ? (query).

Note the single quote that is used for variables.

Now type

showMatches = true
member('X, 'john :: 'mary :: 'nil)?
more
more

What output do you get?

Step 2 Part 2

Now comes the hard part: Put together a complete trace of what the interpreter does. In each step, you can choose from

Use the same substitution that the Scala interpreter uses. When I ran it, the trace output started with

unify 'X with 'john = true
unify 'X16 with 'john = true
unify 'Xs17 with 'mary :: 'nil = true

My solution would be

Step 1. Push member(X, cons(john, cons(mary, nil))) on goal stack

Step 2. Choose rule member(X, cons(X, Xs)).

Step 3. Rename into member(X16, cons(X16, Xs17)).

Step 4. Use unification: X = X16, john = X16, Xs17 = cons(mary, nil) solves as X = john, X16 = john, Xs17 = cons(mary, nil).

Step 5. Unification with fact was success. Display result.

Step 6. Choose rule member(X, cons(Y, Ys)) :- member(X, Ys).

...

Step 3: Arithmetic

  1. Consider this definition of a factorial predicate. FAC(N,M) means that M = N!. (Remember, we need a predicate, not a function, at the top level in Prolog.)
    factorial(0, 1).
    factorial(N, F) :- N > 0, factorial(N-1, F1), F is N * F1.

    Try it out. What is the result of fac(3,X)?

  2. Use the text-based tracer to trace to the step
    3-1-1-1 > 0? 

    Does it succeed? Does it fail? If so, why? What happens next?

  3. When you are done tracing, issue the query
    3-1-1-1 > 0.

    at the Prolog interpreter. What result do you get?

  4. Ok, so why did the recursive factorial fail? (Hint: Try unifying factorial(3-1-1-1,X), that is, factorial(sub(sub(sub(3, 1), 1, 1), X) with factorial(0, 1).)
  5. Fix factorial by forcing evaluation of the arithmetic. What is your code for factorial now? Confirm that factorial(3, X) works.
  6. Try factorial(X,6). What happens?
  7. That's disappointing, but if you think about it, there is no way Prolog could have figured out the answer. Except...
  8. ...by trying all the possible answers. Here is how that works:
    solvefac(N,M) :- numlist(1, M, L), member(N, L), factorial(N, M).

    Try out solvefac(X,6). Explain why it works. (To see what numlist does, just run numlist(1, 6, X).)

Step 4: The Game of Nim

  1. In the game of Nim, two players alternately remove marbles from a pile of marbles. In each turn, a player must remove at least one marble, and at most half the marbles. The player who is left with one marble loses. We will represent the game state by a list of o functors, such as [o,o,o,o,o]. Your task is to write a predicate move(F, T) that checks whether one can legally move from game state F to game state T. For example,
    move([o,o,o,o,o],Y).
    Y = [o,o,o] ;
    Y = [o,o,o,o] ;
    fail

    Hint: It is very easy to check whether T at least one less than F:

    append(S, _, F), append(T, [o], S)

    It is also easy to check that T is at most half as long as F. Append it to itself and check that you can still append more to get F.

    What is your move predicate?

  2. A position is a winning position if the player can force a win, no matter what the opponent does. In Prolog, this is very easy to check:
    win(X) :- move(X,Y), not(win(Y)).

    For example,

    win([o,o,o,o,o]).
    true ;
    fail.

    Try out marble lists of length 1 to 10. Which ones are winning positions?