CS 2360 - March 20, 1997

Sample Final Exam Questions


Here are examples of the types of questions one might find on the
upcoming final exam.  While this gives you some idea about the 
kinds of knowledge you might need or the complexity of individual 
questions, you shouldn't make assumptions about the length
of the exam based on what you see below.  Also, don't assume that
because some topic doesn't appear below that it won't appear on
your exam this Thursday.  This exam is comprehensive, and everything
we've covered in class or in the notes will be fair game.

And no, we won't be posting sample answers to these sample questions.


1.  (20 points)  Write a function called shuffle which takes two 
lists as input (assume both lists have the same length) and returns 
one list which contains the first element of the first list followed 
by the first element of the second list followed by the second element 
of the first list and so on, like this:

? (shuffle '(A K Q) '(J 10 9))
(A J K 10 Q 9)

Write two different versions of this function -- one using iteration 
and one using recursion.


2.  (5 points)  Scheme evaluates function calls a little bit differently 
than LISP does.  Explain.


3.  (10 points)  A queue is a list data structure in which elements are 
added to one end and removed from the other end.  Thus, in contrast to 
a stack, which imposes a last-in-first-out (LIFO) ordering on its members, 
a queue imposes a first-in-first-out (FIFO) ordering on its members.  
Your task here is to construct an operator in Common LISP for this new 
abstract data type.  This operator is called enqueue, which puts an 
element on the "back end" of a list.  Here's how it works:

? (setq x '(a b c))
(A B C)
? x
(A B C)
? (enqueue 'd x)
(A B C D)
? x
(A B C D)
? 


4.  (10 points)  In Common LISP, construct your own iterative version of 
the predefined function member using dolist.  


5.  (10 points)  Use dotimes as the primary control structure in 
constructing your own version of the predefined Common LISP 
function nthcdr.


6.  (10 points)  Use mapcar as the primary control structure in 
constructing your own version of the predefined Common LISP function subst.


7.  (10 points):  Common LISP has several functions which generate 
a new symbol each time they're called.  For example, consider the 
following calls of the function gentemp:

? (gentemp)
T0

? (gentemp)
T1

? (gentemp)
T2

In order to make this work, functions like gentemp need to have access 
to an integer generator -- a function which returns the next integer 
in sequence each time it is called.  Using a lexical closure, construct 
a function called make-integer-generator which when called will return an 
executable function body that can be bound to a symbol.  Then construct a 
function get-next-integer which takes as a parameter a symbol that is 
bound to an integer generator and returns the next integer in the 
sequence for that specific integer generator.  If they work the way 
they're supposed to, the functions would behave like this:

? (setf foo (make-integer-generator))
#

? (setf bar (make-integer-generator))
#

? (get-next-integer foo)
0

? (get-next-integer foo)
1

? (get-next-integer bar)
0


8.  (20 points)  Below and on the next page is printed the mini-Scheme 
interpreter from the last homework assignment.  This time, some additional 
parts have been added to interp, but some other parts are now missing, 
namely the code for SET! and QUOTE.  In the space below, provide the 
Common LISP code that will make these two functions work.


The mini-Scheme interpreter:

(defun interp (x &optional env)
  (cond
   ((symbolp x) (get-var x env))
   ((atom x) x)
   ((case (first x)
      (QUOTE [** what goes here? **])
      (BEGIN (last1 (mapcar #'(lambda (y) (interp y env))
                            (rest x))))
      (SET!  [** what goes here? **])
      (IF    (if (interp (second x) env)
                 (interp (third x) env)
                 (interp (fourth x) env)))
      (LAMBDA (let ((parms (second x))
                    (code (maybe-add 'begin (rest (rest x)))))
                #'(lambda (&rest args)
                    (interp code (extend-env parms args env)))))
      (t      (apply (interp (first x) env)
                     (mapcar #'(lambda (v) (interp v env))
                             (rest x))))))))
(defun set-var! (var val env)
  (if (assoc var env)
      (setf (second (assoc var env)) val)
      (set-global-var! var val))
  val)

(defun get-var (var env)
  (if (assoc var env)
      (second (assoc var env))
      (get-global-var var)))

(defun set-global-var! (var val)
  (setf (get var 'global-val) val))

(defun get-global-var (var)
  (let* ((default "unbound")
         (val (get var 'global-val default)))
    (if (eq val default)
        (error "Unbound scheme variable: ~a" var)
        val)))

(defun extend-env (vars vals env)
  (nconc (mapcar #'list vars vals) env))

(defparameter *scheme-procs*
  '(+ - * / = < > <= >= cons car cdr not append list read member
      (null? null) (eq? eq) (equal? equal) (eqv? eql)
      (write prin1) (display princ) (newline terpri)))

(defun init-scheme-interp ()
  (mapc #'init-scheme-proc *scheme-procs*)
  (set-global-var! t t)
  (set-global-var! nil nil))

(defun init-scheme-proc (f)
  (if (listp f)
      (set-global-var! (first f) (symbol-function (second f)))
      (set-global-var! f (symbol-function f))))

(defun maybe-add (op exps &optional if-nil)
  (cond ((null exps) if-nil)
        ((length=1 exps) (first exps))
        (t (cons op exps))))

(defun length=1 (x)
  (and (consp x) (null (cdr x))))

(defun last1 (list)
  (first (last list)))

(defun scheme ()
  (init-scheme-interp)
  (loop (format t "~&==> ")
        (print (interp (read) nil))))




Copyright 1997 by Kurt Eiselt.  All rights reserved.

Last revised: March 14, 1997