Logic Languages: Extra Credit: A Simple Prolog Interpreter (30pts)

For this part, we'll use Scheme to build a simplified Prolog interpreter. It does not do any of the fancier things that real Prolog allows (like cut, assertions, etc) --- it just knows how to do basic Prolog problem solving. The aim of this exercise is to give you a very keen understanding of what prolog is doing internally, and in particular, the "Flow of Satisfaction" that is at the heart of the Prolog solving process.

Given the straightforward nature of Prolog evaluation, this is not difficult. Actually, the hardest part is some of the tricky helper functions (like unification). To ease this challenge, I will be giving you my implementations of some of these "hard but peripheral to the central focus on logic programming concepts " functions for you to use.

Some basic caveats, basically emphasizing that this is a BASIC prolog interpreter:

In short, it just has to be able to prove simple things, as shown in the example files linked below!

Here are the basic functions your interpreter has to support:

(load-facts "filename.txt").

The load-facts function simply load a fact base from the designated file. The file simply contains an ordered list of facts and rules, one per line. Here is a sample fact base file you can look at to get the idea. NOTICE that (because we don't want to mess with upper and lower case distinctions), variables in our implementation are simply atoms preceded by a "?" (question mark). This makes them nice and easy to recognize (readability) and to identify in Scheme....I give you the "isvar?" function (see below).

(prove <goal or goal-list>).

The prove function emulates the interpreter prompt in prolog, ie, you use it to submit the goal(s) you want proved. Note that prove is CLEVER in that you can pass it either a single goal, or a list of (conjunctive) goals to prove; this is just nice bit of syntactic suger to make talking to this thing easier! If the proof process fails, prove should return "fail". If the proof process suceeds, it should return the list of bindings it made in doing the proof (which might be empty if none were called for).

Here is a sample run of PROVE in action, to give you the idea. As you can see, nothing super fancy --- just standard flow of satisfaction!

There are a number of challenging sub-parts to PROVE, primarily centered around dealing with unification pattern matching. To keep you focused on the primary goal of this assignment (understanding the prolog "flow of satisfaction" model), I'll go ahead and give you the key functions for this. Looks dense, but it's 90% comments so that you can UNDERSTAND what these functions do, and use them appropriately! UNIFY does some pretty tricky work of unifying two predicates. The UNIQUE function should be called during your load file to clean up the fact base you're bring in, i.e., to make all variables in that fact base unique, which saves lots of headaches in unification. Play with each of these functions some on test input to see how they work...then you'll can pop them into your code.

Hint: elegance is everything. Make SURE you understand the prolog flow of satisfaction before you start. The problem can be solved in about a page of code! Hint: let the recursive call stack handle the backtracking!

To Turn In: Due: at or before Final Exam

  1. Hardcopy packet, in this specific order:
  2. Electronic Submission of your code by email to me: