#lang racket ; lexical scope examples ; Example 0 (define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) ; Example 1 (define x1 1) (define f1 (lambda (y1) (let ([x1 (+ y1 1)]) (lambda (z1) (+ x1 y1 z1))))) (define z1 (let ([x1 3] [g1 (f1 4)] ; ALWAYS adds 4 and 5 to its argument [y1 5]) (g1 6))) ; Example 2 (define f2 (lambda (g2) (let ([x2 3]) (g2 2)))) (define x2 4) (define h2 (lambda (y2) (+ x2 y2))) (define z2 (f2 h2)) ; Why lexical scope? ; We can use whatever local variable names we want. ; They never accidentally refer to something else. ; These two functions always produce equivalent results on the same input. (define (f3 y) (let ([m (+ y 1)]) (lambda (z) (+ m y z)))) (define (f4 y) (let ([q (+ y 1)]) (lambda (z) (+ q y z)))) (define m 32) ;; irrelevant (define a3 ((f3 7) 4)) (define a4 ((f4 7) 4)) ; Same deal with f5 and f6. (define (f5 g) (let ([x 3]) ; irrelevant (g 2))) (define (f6 g) (g 2)) (define n 32) ;; irrelevant (define a5 (f5 (lambda (y) (+ n y)))) (define a6 (f6 (lambda (y) (+ 32 y)))) ; Being able to pass closures that have free variables (private data) ; makes higher-order functions /much/ more useful. (define (filter f xs) (if (null? xs) null (if (f (car xs)) (cons (car xs) (filter f (cdr xs))) (filter f (cdr xs))))) (define (greater-than-x x) (lambda (y) (> y x))) (define (no-negs xs) (filter (greater-than-x -1) xs)) (define (all-greater xs n) (filter (lambda (x) (> x n)) xs)) ; Good use of closures can improve efficiency with higher order functions. (define (all-shorter-than-1 lists mine) (filter (lambda (xs) (< (length xs) (length mine))) lists)) (define (all-shorter-than-2 lists mine) (let ([len (length mine)]) (filter (lambda (xs) (< (length xs) len)) lists)))