CIS-4/681 – Assignment 1 – LISP Due: Tuesday, September 28 – 2 weeks This assignment asks you to write a number of simple lisp functions which manipulate lists in various ways. The material you hand in should include both the function definitions and the results of applying the functions to some test data. Keep in mind that you should be writing your functions recursively with no use of setf, prog, or goto’s. The material you hand in should include both the function definitions and the results of applying the functions to some test data. It is easiest if you can show your testing results just after the function definitions on your hard copy. One way is to use the function print-eval which would allow you to specify all of your test cases and then run them. You will find this function (and documentation for how to use it) in the lisp-init.lisp file. You will need to print out the lisp-listener buffer after running print-eval, and then you could cut-and-paste them into your file for handing in. Other methods also work, but most require some cutting and pasting. Please be sure to remember that falsifying the output of your program is a serious breach of the code of ethics and will be dealt with severely. In addition to the hard-copy that you hand in, you should send an electronic version of your lisp file only (i.e., no test cases) to trnka@cis.udel.edu. This will allow the TA (Keith) to run your functions if necessary. Please be careful that you use the exact function names given in this assignment to make grading easier. Again, the lisp functions in the soft-file must match the ones on the hard copy exactly, otherwise it is a serious violation of the code of ethics. 1. Ordered Binary Trees in Lisp – 15 points – It is quite easy to represent ordered binary trees using lisp lists. We can let nil represent the empty binary tree and the list of three elements (info left right) represent a binary tree whose information is info, whose left child is the binary tree left and whose right child is the binary tree right. Recall that an ordered binary tree is one where at each node in the tree, all information to the left of a node is less than (or equal to) info and all information to the right of a node is greater than info. For example, the following ordered binary tree: 7 / \ / 5 / \ / -2 \ 9 \ 6 \ \ 12 might be represented as follows: (7 (5 (-2 nil nil) (6 nil nil)) (9 nil (12 nil nil))) This problem asks you to write a number of functions to build and access ordered binary trees where an integer is stored at each node in the tree. Write the following functions: (a) (is-in-tree? n bt) – this function returns T if the integer n is in the ordered binary tree bt. It returns nil otherwise. (Note: the search should be intelligent in that it should take advantage of the fact that bt is an ordered binary tree!) (b) (insert n bt) – this function returns a new ordered binary tree formed by adding the integer n to the ordered binary tree bt. 1 (c) (insert-list list-of-integers bt) – this function returns the ordered binary tree formed by inserting each of the integers in list-of-integers into the ordered binary tree bt. The integers are inserted in left to right order. (d) (make-bt list-of-integers) – this function returns an ordered binary tree formed from the list of integers in the given order. Some examples are: (setf t1 (make-bt ’(2 1 3))) ---> (2 (1 nil nil) (3 nil nil)) (setf t1 (insert 4 t1)) ---> (2 (1 nil nil) (3 nil (4 nil nil))) 2. rep-seq – (5 points) – write a function that takes a list of positive integers as its argument and returns a list of sublists where the ith sublist consists of the ith integer in the argument list repeated j times, where j is the value of the ith integer. (Hint: You may want your function rep-seq to use another function rep that takes two arguments, j and k, and returns a list containing k repetitions of argument j.) Example: > (rep-seq ’(3 5 3 1)) ((3 3 3)(5 5 5 5 5)(3 3 3)(1)) 3. sum-numbers – (10 points) – write a function that takes an arbitrarily embedded list containing both numbers and symbols that returns the sum of the numbers occurring (at any level) in the list. For example: > (sum-numbers ’(1 a (b (c 3) (((4)) b) 5))) 13 4. (typer s-exp) – (10 points) – (from Brooks p2.5) write a function typer that takes an arbitrarily complex s-expression and returns a new one with the same “shape” but with only symbols NUMBER and SYMBOL corresponding to the type of the original atoms in the list. Examples: > (typer ’(a b 3 d)) (SYMBOL SYMBOL NUMBER SYMBOL) > (typer ’((a 2.3) (((b c)) 3))) ((SYMBOL NUMBER) (((SYMBOL SYMBOL)) NUMBER)) 5. count-cells – (10 points) – write a function that computes the number of list cells a list uses. An atom uses no cells. The empty list, nil, uses no cells. A list uses 1 cell for each of its members in addition to the cells each of its members use. E.g., (count-cells (count-cells (count-cells (count-cells (count-cells (count-cells ’(one two 3 4 5)) ---> 5 ’(one (two) 3 4 5)) ---> 6 ’(defun round (n) (fix (add n 0.5)))) ---> 10 nil) ---> 0 ’(1 2 nil)) ---> 3 ’one) ---> 0 6. pfeval – 15 points – write a function which takes a list containing a postfix expression and returns the value of that expression. The evaluation of the postfix expression should use a stack which is easily implemented as a list. You will probably want to write a helping function whose arguments are the stack and a (partial) postfix expression to do the actual evaluation. You may assume that the postfix expression is well formed and contains only numbers and the binary operators -, +, *, ^, and /. Example: (pfeval ’(16 2 3 ^ / 4 5 * + 16 3 * -)) --> -26 2 7. mobilep – 15 points – (from Winston/Horn Problem 4-10) A mobile is a form of abstract sculpture consisting of parts that move. Usually it contains objects suspended in mid-air by fine wires hanging from horizontal beams. We can define a particularly simple type of mobile recursively as either a suspended object, or a beam with a sub-mobile hanging from each end. If we assume that each beam is suspend from its midpoint, then in order for the mobile to be balanced, the two submobiles hanging from a beam must have the same weight. We can represent such a mobile as a binary tree. Single suspended objects are represented by numbers equal to their weight, while more complicated mobiles can be represented by a three-element list. The first element is a number equal to the weight of the beam, while the other two elements represent sub-mobiles attached at the two ends of the beam. A mobile should be balanced. This means that the two mobiles suspended from opposite ends of each beam must be equal in weight. Define mobilp, a function which determines whether a mobile is balanced. It returns NIL if it is not, and its total weight if it is. (HINT: I used a let statement in my solution which held the weight of the left and right mobiles.) So for example: (mobilep ’(6 (4 (2 1 1) 4) (2 5 (1 2 2)))) ---> 30 8. chomper – (20 points) – The purpose of this function is to mimic the actions of a simple cybernetic animal that lives in a one-dimensional world of zeros and ones. Ones represent things to eat, and the animal seeks them out and eats them until none are left. An interaction with chomp might look like this: >(chomper ’(0 1 0 1 0 0 (0 1 0 (0 1 0 (0 1 0 (0 1 0 (0 1 > (0 > 0 (0 V 0 (0 < 0 (0 0 < (0 0 0 (0 0 0 (0 0 0 (0 0 0 (0 0 0 (0 0 0 (0 0 0 That’s NIL 1 0 0 > 1 1 1 0 > 0 1 1 1 > 0 0 1 1 > 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 < 0 0 0 1 1 0 < 0 0 1 1 0 0 < 0 1 1 0 0 0 < 1 1 0 0 0 0 < 1 0 0 0 0 0 < 0 0 0 0 0 V all, folks. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 V 1 1 0 0)) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) 0) Let’s notice a couple of things about the Chomper. First, Chomper itself is represented in one of three ways, depending on its current state. If Chomper is not currently moving in a direction, it is represented as a V. If it is moving left, it is represented as a >, and if it is moving right, a <. Thus the list given to the chomper function consists of a series of zeros and ones and one instance of Chomper in one of its three states. Suppose Chomper is in its V state. Then, if there is any food to its left (i.e., there are any ones to its left) then it will switch to a state in which it is moving left. If there is no food to its left (i.e., there are NO ones to its left) but there is food to its right, it will switch to a state in which it is moving right. If there is no food left for it to consume (when it is in its v state), it will print out the message That’s all folks. and return nil. 3 Once Chomper is started in one direction or another, it will continue in that direction as long as there is any food in that direction at all. When food runs out in that direction, Chomper will not move but will switch into its V state. As long as there is food in a particular direction, Chomper will move one in that direction, converting ones into zeros as they are met. The state of Chomper is printed out with each change to its state. You will need a number of helping functions with this procedure! I used a let to hold: (1) the list to the left of chomper, (2) a list containing chomper itself, (3) the list to the right of chomper. Then the function prints and returns different things depending on what chomper looks like and whether or not there is food to its left or right. 4