CSC 324 Tutorial Week 4 ======================= define/let/letrec ================= Question -------- Consider: (define a 1) ; declare a if not already ; evaluate 1 ; assign 1 to a Describe any problems with the following, evaluating the ones which have a value: (define b b) ; error, no value for b (define c (lambda () c)) ; okay, haven't *called* right side yet c => (c) => ((c)) => (define d ((lambda () d))) ; error (define e (lambda () (e))) ; okay e => (e) ; never returns Question -------- Consider: (let ((a (+ a 2))) ; Evaluate (+ a 2) in parent environment, ; declare local a shadowing parent a, ; initialize local a a) => 3 Describe any problems with the following, evaluating the ones which have a value, and describing what they display: (let ((f f)) ; no f in scope f) (define f 3) (let ((f (lambda () f))) (f)) => 3 To get behaviour more like define, but for local variables, use letrec: (define f 3) (letrec ((f (lambda () f))) (f)) => Capturing (some) linear recursion on (linked) lists =================================================== Question -------- Implement map. Answer ------ (define map (lambda (f l) (if (null? l) '() (cons (f (car l)) (map f (cdr l)))))) Question -------- Define a two procedures: . length, that given a list computes the number of elements in the list, and . append, that given two lists concatenates them. Answer ------ (define length (lambda (l) (if (null? l) 0 (+ 1 (length (cdr l)))))) (define append (lambda (l1 l2) (if (null? l1) l2 (cons (car l1) (append (cdr l1) l2))))) Map, length and append are similar. The differences are: (1) result when null (2) how current element and result of rest combine Identify (1) and (2) for each procedure. Express (2) as a procedure as in the following form: (lambda (current-element result-of-rest) ...) Answer ------ map: '() (lambda (e r) (cons (f e) r)) length: 0 (lambda (e r) (+ 1 (length r))) append: l2 cons Question -------- Define a procedure accumulate that: takes a list and the two pieces of information (1) and (2) returns the corresponding result Answer ------ (define accumulate (lambda (l initial combiner) (if (null? l) initial (combiner (car l) (accumulate (cdr l) initial combiner))))) Question -------- Implement length, map and append using accumulate. Answer ------ (define map (lambda (f l) (accumulate l '() (lambda (e r) (cons (f e) r))))) (define length (lambda (l) (accumulate l 0 (lambda (e r) (+ r 1))))) (define append (lambda (l1 l2) (accumulate l1 l2 cons))) Question -------- Notice the recursive call in accumulate changes only its first argument. Make a helper procedure accumulate-helper inside the accumulate procedure. It takes one argument, the list, and does the recursion. Then have accumulate call the helper with the list given to accumulate. Depending on how the language is implemented, this might be faster, might be slower. Answer ------ (define accumulate (lambda (l initial combiner) (letrec ((accumulate-helper (lambda (l) (if (null? l) initial (combiner (car l) (accumulate-helper (cdr l))))))) (accumulate-helper l))))