CS 37
Clab 5: Invariants, exponentiation, functions as first-class objects
Here are some solutions to last clabs work. Make sure you understand
them thoroughly. If not, ask me about them.
;;;some test lists
(define a '(cat dog amt))
(define b '(horse dog))
(define d '(horse dog cat ant dog x y x z))
;;; memb? returns #t if el is an element of list lst
;;; returns #f otherwise. Assume lst is a list.
(define (memb? el lst)
(cond
((null? lst) #f)
((equal? el (car lst)) #t)
(else (memb? el (cdr lst)))))
;; remove-first returns a list with the first occurrence of
;; sym removed from list l:
(define remove-first
(lambda (sym l)
(cond
((null? l) '())
((equal? (car l) sym) (cdr l))
(else (cons (car l) (remove-first sym (cdr l)))))))
Notice how we cons up a solution after cdring down one of the
parameters. This kind of structure is common to many list processing
solutions.
Here are some more solutions
;; remove-all returns a list with all occurrences of sym
;; removed from the list l
(define remove-all
(lambda (sym l)
(cond
((null? l) '())
((equal? (car l) sym) (remove-all sym (cdr l)))
(else (cons (car l) (remove-all sym (cdr l)))))))
The above generates a recursive process to solve the substition remove-all
problem. You can prove it is correct by doing mathematical induction
on the length of the list. Here next is an iterative solution to
the remove-all problem. The comment before remove-all-iter is called
an invariant. We design remove-all-iter to maintain the truth of the
invariant in terms of the current values of the parameters mentioned
at any invocation of remove-all-iter. We can use this to prove the
correctness of remove-all-iter.
;; remove-all-i returns a list with all occurrences of sym
;; removed from the list l
(define remove-all-i
(lambda (sym l) (remove-all-iter sym '() l)))
;; remove-all-iter returns a list that consists appending
;; the list partdonelis to the list that results from
;; removing all occurences of sym from the list todolis.
;; inv: if called by remove-all-i as above, appending
;; partdonelis to the list that results from removing all
;; occurences of sym from todolis yields a new list that
;; is the same as l with all occurences of sym removed
(define remove-all-iter
(lambda (sym partdonelis todolis)
(cond
((null? todolis) partdonelis)
((equal? sym (car todolis))
(remove-all-iter sym partdonelis (cdr todolis)))
(else
(remove-all-iter sym
(append partdonelis (list (car todolis)))
(cdr todolis))))))
Now work through the 3 different exponential procedures given on pages
44-46. Use trace on them (you may want to trace * also) to help you
understand what they are doing. Make sure you understand how each of
them works and that (1) the first one requires O(n) time and space,
(2) the second one requires O(n) time and O(1) space, and (3) the
third one, fast-exp, requires O(log n) time and space. Ask questions
if you have them.
What is a good invariant for expt-iter?
At some point, I'll say a few words about invariants and Functions as
first-class objects. When I am not talking work on
the following stuff.
Now carefully review the material on pages 73bottom-74.
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-12.html#%_sec_1.3.4
Define deriv as in the
text on p. 74.
(define (deriv g)
(lambda (x)
(/ (- (g (+ x dx)) (g x))
dx)))
(define dx .00001)
(define square (lambda (x) (* x x)))
(define cube (lambda (x) (* x x x)))
Note that deriv is a procedure that takes one argument, a
function, and returns a function that is an approximation to the
derivative of the first argument. deriv expects to be executed in an
environment where dx is defined to be a small positive real number
(e.g. 0.00001).
You should have the functions square and cube defined from before. If
not, define them now. Define dx to be 0.00001.
Now evaluate
(define Dsquare (deriv square))
Dsquare is a function
that is an approximation to the derivative of x^2. That is Dsquare is
a function that should be very close to the function 2x. Try
evaluating Dsquare on some values and check that it does behave like
an approximation to the function 2x. Now evaluate
(define g (deriv cube))
g should be an approximation to the function 3x^2 which
is the derivative of x^3. Check it on a few values.
The composition of 2 functions f and g, sometimes written fg is
defined by fg(x) = f(g(x)). That is first apply g to x, then apply f
to the result. For example if f(x) = x^3 and g(x) = 1 + x, then
fg(x) = (1 + x)^3. We want to define a procedure that takes two
functions as arguments and returns the composition of those two
argument functions. Here is a start:
;;;given the 2 functions f and g, compose returns the composition fg
(define (compose f g)
(...you fill in this part)
;;; for convenience we will define the function 1+ which increments
;;; its argument by one.
(define 1+ (lambda (x) (+ 1 x)))
For example:
> (1+ 7)
8
After you have successfully defined compose, you should be able to
evaluate:
(define h (compose cube 1+))
If you did it right h should
be the function h(x) = (1 + x)^3.
Try it and check h for a few values. Try some other compositions.
Ask any questions you may have.