Got Questions? Try office hours, email or the newsgroup git.cc.class.3411.
Recursive Data Structures
For your first programming assignment this quarter, you will write a collection of rules for representing and manipulating binary trees in Prolog. You will use Prolog's two primary data structuring mechanisms for this assignment: symbolic structures and lists. Prolog structures are something like records in imperative programming languages but they are more powerful. Prolog lists are similar to lists in Lisp. Both structures and lists are fundamentally recursive. Structures are the more basic mechanism because the Prolog list notation can be viewed as "syntactic sugar" for a more primitive structure-based representation of lists.
Here is a fact represented by a simple Prolog structure:
book( moby_dick, author( herman, melville ) ).
This fact can be visualized as a binary tree but structures can, in general, have any number of members ("arity"). As usual, things get more interesting when we allow structures to contain logical variables. Structures with self-similar components are easily manipulated by recursive rules so we call them "recursive structures." Binary trees can be easily represented in Prolog by recursive structures. Here is a simple rule that defines binary trees in Prolog:
/** binary_tree(Tree) :-Notice there are no constraints on the first component Element, it can be anything, but that the second and third components must themselves be binary trees. As a base case, void is considered a binary tree.
Tree is a binary tree. */
binary_tree(void).
binary_tree(tree(Element,Left,Right)) :-
binary_tree(Left), binary_tree(Right).
Given our recursive tree definition, we can pretty easily write a rule that determines if a given element appears anywhere in a given binary tree:
/** tree_member(Element,Tree) :-This rule precisely and concisely encodes the three possible cases: either the element in question is the root or it appears in the left subtree or it appears in the right subtree.
Element is an element of the binary tree Tree. */
tree_member(X,tree(X,Left,Right)).
tree_member(X,tree(Y,Left,Right)) :- tree_member(X,Left).
tree_member(X,tree(Y,Left,Right)) :- tree_member(X,Right).
Here is another recursive rule that implements a preorder traversal of
/** preorder(Tree,Pre) :-This rule is a bit more complicated and uses the Prolog list notation ([a,b,c]). Prolog has a special operator (|) (sometimes called "split") that can be used to break a list apart into its head and tail. The split operator can also be used to put a list together like CONS in Lisp. We will talk more about the list notation in class and you can read about it in your text and the supplemental handout.
Pre is a list of elements of Tree accumulated during a
preorder traversal. */
preorder(tree(X,L,R),Xs) :-
preorder(L,Ls), preorder(R,Rs), append([X|Ls],Rs,Xs).
preorder(void,[]).
Here is the rule for append:
/** append(Xs,Ys,XsYs) :-What Am I Supposed to Do?
XsYs is the result of appending the lists Xs and Ys. */
append([],Ys,Ys).
append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs).
Implement the following rules:
Create a single file called tree that contains all the facts and rules for the assignment. "Consult" this file each time you start prolog. Begin with VERY SIMPLE RULES and gradually add complexity and more rules. The "development environment" for our version of Prolog is hard to love. Do the best you can with it. Brian has prepared a nice Web page with helpful hints and we will provide additional supporting material, including several demo programs, in the coming weeks.
You will need to use one trick to make life easier while developing your programs. Since typing in complex tree structures is tedious and error prone, you should define a few "named trees" like this at the beginning of your tree module:
/* Define a few trees to work with. */Make sure you get the commas and parentheses correct. Once defined you can use these named trees to test your rules like this:
tree1(tree(a,tree(b,void,void),tree(c,void,void))).
tree2(tree(d,tree(e,void,void),tree(f,void,void))).
tree3(
tree( a,
tree( b,
tree(e,void,void),
tree( f,
tree(g,void,void),
void
)
),
tree(c,void,void)
)
).
prolog
?- [tree]. /* consult the
file containing the tree facts and rules */
?- tree2(A), tree_element(e,A). /* does e appear in
tree2? */
Helpful Advice
You have 4 weeks to complete this assignment! That's a lot of time but it takes awhile for the "Prolog way of thinking" to sink in. Work steadily and incrementally. Spend a bit of time on a regular basis working with the Prolog interpreter, reading reference material and working through the assignment. Ask questions when strange things happen. Stay-tuned to the newsgroup for turnin details and related assignment announcements.
Good luck! Start Early! Use Office Hours Often!