Overview
I would certainly appreciate suggestions of other extra credit activities (preferably via email).
_If we have a function in the output, what happens? For example,
when do the addition and call to list get evaluated in the following?__
(define function-kernel
(lambda (so-far remaining)
(write (list 'kernel so-far remaining))
(newline)
(if (null? remaining)
so-far
(kernel (+ 1 so-far) (cdr remaining)))))
General rule in Scheme: Evaluate all of the parameters before calling the function. (+ (* 2 3) (- 4 5)).
Applying that general rule, we do the (+ 1 so-far) before we recurse we do the cdr before we recurse, and we build the list before we write.
Is there a way to show it undone?
Can we see an expression being built up?
If you do something strange to build it, as in the following.
(define function-kernel
(lambda (computation so-far remaining)
(write (list 'kernel computation so-far remaining))
(newline)
(if (null? remaining)
so-far
(function-kernel (list '+ 1 computation) (+ 1 so-far) (cdr remaining)))))
You just said that “we evaluate the parameters and then apply the procedure”. Are there exceptions to that?
Yes.
if,and,orare all exceptions.ifevaluates the first parameter and then decides which of the other two to evaluate.orevaluates one at a time until it hits truish (or runs off the list),andevaluates one at time until it hits #f (or runs off the list).
cond,lambda,quote
Do we have to document problem 8 on HW 7?
Yes. Documentation is good for your soul. Or brain. Or something.
smallest(define smallest (lambda (lst) (cond [(null? (cdr lst)) (car lst)] [(< (car lst) (smallest (cdr lst))) (car lst)] [else (smallest (cdr lst))])))
Observation: If the list is ordered from largest to smallest, the amount of time doubles each time we add an element. 25 elements take about 1 second, 35 elements would take about 1000 seconds, 45 elements would take 1000000 seconds (over 11 days).
Why? If it’s in descending order, we always hit the else statement. The else statement is contributing to the cost. Because we recurse twice. And those also have to recurse twice. And so on and so forth.
How can we fix this?
Option 1: Completely change the structure to our “reduce” structure”
(define smallest
(lambda (lst)
(if (null? (cdr lst))
(car lst)
(min (car lst) (smallest (cdr lst))))))
Option 2: Try using and and or? (Still needs work.)
Option 3: Use let.
(define smallest
(lambda (lst)
(if (null? (cdr lst))
(car lst)
(let ([smallest-in-cdr (smallest (cdr lst))])
(if (< (car lst) smallest-in-cdr)
(car lst)
smallest-in-cdr)))))
Option 4: Use a helper procedure (with named let)
See below.
Morals: If you can avoid it, don’t have two identical recursive calls in
the same procedure. (More generally, try to avoid identical calls of any
sort in your procedure.) let is your friend.
(define my-reverse
(lambda (lst)
(if (null? lst)
null
(append (reverse lst) (list (car lst))))))
Morals
Named let is designed for when you want tail-recursive helper procedures.
When you think about tail-recursive helpers, you have
smallest)In named lets
(let NAME ([column1 init1]
[column2 init2]
[column3 init3]
...)
(if BASE-CASE-TEST
base-case
(NAME (update column1) (update column2) ...)))
(define smallest2
(lambda (lst)
(let kernel ([remaining (cdr lst)]
[smallest-so-far (car lst)])
(if (null? remaining)
smallest-so-far
(kernel (cdr remaining)
(min smallest-so-far (car remaining)))))))
No lab writeup today.