CS 491/591 Advanced Scheme Programming and Implementation

Homework 1 (Spring 2004)

  1. The definition of a function, foo, is a <tail definition> if it has the following form:

    (define foo (lambda (<symbol>*) <tail wrt foo>))

    where <symbol>* is zero or more symbols and an expression is <tail wrt foo> if it is not an application of foo:

    <contains no foo applications>

    or

    if it is an application of foo to zero or more expressions which contain no applications of foo:

    (foo <contains no foo applications>*)

    or

    if all applications of foo are contained in expressions which are (themselves) tail recursive with respect to foo and which occur in any of the following contexts:

    where <contains no foo applications> is an expression which contains no applications of foo,and <contains no foo applications>* is zero or more expressions which contain no applications of foo.

    Write a function, tail-definition?, which takes an expression, expr, as an argument, and returns #t if the expression is a <tail definition> and #f otherwise. For example:

    > (tail-definition? '(define fact (lambda (x acc) (if (= x 0) acc (fact (- x 1) (* x acc))))))
    #t
    > (tail-definition? '(define fact (lambda (x) (if (= x 0) 1 (* x (fact (- x 1)))))))
    #f
    > (tail-definition? '(define member? (lambda (item ls) (and (not (null? ls)) (or (eq? item (car ls)) (member? item (cdr ls)))))))
    #t
    >
    
    Hint: Divide and conquer. Write helper-functions, tail-wrt? and no-applications-of?. Both take a function name, fname, and an expression, expr, as arguments. tail-wrt? returns #t if expr is tail with respect to fname and #f otherwise. no-applications-of? returns #t if there are no applications of fname in expr, and #f otherwise.

  2. Write a function, curry-skip, with the following behavior:
    > ((curry-skip 0) 'foo)
    foo
    > (((curry-skip 1) 'foo) 'bar)
    bar
    > ((((curry-skip 2) 'foo) 'bar) 'baz)
    baz
    >
    
  3. Write iterate-to-fixedpoint which takes as arguments: 1) A function of one argument, f; 2) A function of two arguments, pred (used to test for convergence); and 3) An initial value, x0. iterate-to-fixedpoint applies f repeatedly to its own output, (f (f (f ... (f x0)))), until the value stops changing (as determined by pred). iterate-to-fixedpoint then returns that value, i.e., it returns a fixedpoint of f. For example,
    > (iterate-to-fixedpoint (lambda (x) (/ (+ x (/ 2 x)) 2)) (lambda (x y) (< (abs (- x y)) 0.00001)) 1.0)
    1.41421
    > (iterate-to-fixedpoint (lambda (x) (if (pair? x) (car x) x)) eq? '(((((a b) c) d) e f g) h))
    a
    >
    
  4. Write make-lookup-function which takes as arguments: 1) A symbol, target; and 2) An s-expression, sexpr, to be searched. make-lookup-function returns a function composed of car's and cdr's that will fetch target out of sexpr. If target is not found in sexpr, make-lookup-function returns #f. If target appears more than once, the returned function should access the first occurence of target (as printed). > (define foo (make-lookup-function 'd '(a (b c (d e) f g) h))) > (foo '(a (b c (d e) f g) h)) d > (foo '(1 (2 3 (4 5) 6 7) 8)) 4 > (define bar (make-lookup-function 'j '(a (b c (d e) f g) h))) > (bar '(1 (2 3 (4 5) 6 7) 8)) #f > (define baz (make-lookup-function 'b 'b)) > (baz 'b) b > (baz 6) 6 >
  5. Define a function clock-maker which creates instances of a class, clock, representing a 12 hour clock, using three restricted-counter objects (See Exercise 12.4 in Springer and Friedman) to represent hours, minutes, and seconds. Clock instances should recognize the following methods: You can test your clock class using the following test routine:
    (define clock-tester
      (lambda ()
        (let ((clock (clock-maker)))
          (letrec
            ((loop
              (lambda (seconds)
                (if (< seconds 3601)
                    (begin
                      (send clock 'tic!)
                      (loop (add1 seconds)))))))
            (send clock 'hours! 11)
            (send clock 'minutes! 3)
            (send clock 'seconds! 47)
            (loop 0)
            (send clock 'display)))))
    
    If your clock is working correctly, it should display 00:03:48.
Recommended due date: Thurs. Feb. 12.