******************************************************************** LEXICAL IMBEDDING (define (myReverse L) (define (myReverse1 L M) (cond ((null? L) M) (#t (myReverse1 (cdr L) (cons (car L) M))))) ; end of myReverse1 (myReverse1 L '())) ; body of myReverse ******************************************************************** LEXICAL SCOPING (set! I 'outside) (define (bar J) (list I J)) (define (foo I) (bar 'p)) ; body of foo (foo 'inside) => (outside p)) ******************************************************************** DYNAMIC TYPING (define (foo X) (cond ((symbol? X) (list X)) ((number? X) (+ X 1)) ((list? X) (reverse X)))) (foo 3) => 4 (foo '(a b c)) => (c b a) ******************************************************************** PASSING FUNCTIONS AS ARGUMENTS. (define (applyToList F L) (cond ((null? L) '()) (#t (cons (F (car L)) (applyToList F (cdr L)))))) (applyToList add3 '(2 3 4)) => (5 6 7) ; applyToList is actually the built in function "map" (map add3 '(2 3 4)) => (5 6 7) (map list '(a b c)) => ((a) (b) (c)) (map + '(2 3 4) (10 20 30)) => (12 23 34) ******************************************************************** (define (integrate F L U N) (let ((DELTA (/ (- U L) N))) (do ((I 0 (+ I 1)) (X L (+ X DELTA)) (SUM 0 (+ SUM (* DELTA (F X))))) ((= I N) SUM)))) (define (square X) (* X X)) (integrate square 0 1 100) => 0.32835 (integrate sin 0 1 100) => 1.99984 ******************************************************************** DEFINING ANONYMOUS FUNCTIONS USING lambda (integrate (lambda (X) (+ (* X X) X 1)) 0 1 100) => 1.82335 (applyToList (lambda (X) (cons X '(b c))) '(1 2 3)) => ((1 b c) (2 b c) (3 b c)) Functions as first-class entities (set! add3 (lambda (X) (+ X 3))) => #[ (2 anon-lambda)) (add3 8) => 11 (define (adder N) (lambda (X) (+ X N))) => adder ((adder 3) 5) => 8 (set! add3 (adder 3)) (set! add10 (adder 10)) (add10 11) => 21 ******************************************************************** FREE VARIABLES IN CLOSURES: Note: I won't require this material in the homework or the final exam. (define (foo) (lambda (X) (list I X))) (set! I 'A) ((foo) 'B) => (A B) (set! I 'C) ((foo) 'B) => (C B) (define (bar I) (lambda (X) (list I X))) ((bar 'Q) 'B) => (Q B) (map (bar 'Q) '(A B C)) => ((Q A) (Q B) (Q B)) ; Note: The binding of I survives the lifetime of the call to bar ******************************************************************** (define (foo) (define (bar I) (lambda (X) (+ X I))) ; bar returns a closure (let ((adder (bar 3))) ; body of foo. bind adder to (bar 3) (adder 2))) ; call adder (foo) => 5 ******************************************************************** (define (foo) (define (bar I) (let ((displayI (lambda () (begin (display I) (newline))))) ; bind variable displayI to the closure that prints out I (displayI) (set! I (+ I 1)) (displayI) (set! I (+ I 1)) (displayI) displayI)) ; bar returns the closure displayI as its value ; end of bar ; body of foo (let ((dd (bar 3))) ; Execute (bar 3) and bind dd to the value it returns (display '(bar has returned)) (newline) (dd) ; call dd. I) ) ; end of foo (set! I 55) (foo) ; prints out "\n 3 \n 4 \n \5 \n bar has returned" and returns 55. ******************************************************************** Closures subvert the normal assumption about relation of function calls in lexical structure (define (a I) (define (b) I) ; body of a (lambda () (b))) (define (c) (let ((f (a 100)) (I 2)) (f))) (c) => 100 c calls a, which creates a closure and returns. Then c calls the closure which calls b which accesses the dead a's value of I. Note that c is able to indirectly call b without an intermediary call to a, which is impossible in standard lexically imbedded language. Note also that variable I is not even mentioned in the text of the closure. ******************************************************************** Use of closures to implement pass by name (define (bar INAME I) (+ (* (INAME) 100) (* (INAME) 10) I)) (define (foo) (bar (lambda () ; Call bar with the closure (begin (set! I (+ I 1)) I)) 7)) (set! I 2) (foo) ; returns 347 This accomplishes the same as the following code implemented with pass by name function foo () { return bar(I++,7); } function bar(J,I) { return (J*100) + (J*10) + I; } foo()