Closures in Scheme

Andy Balaam

Contents

Functions in functions


(define (sum-of-squares x y)

    (define (square a)
        (* a a))

    (define (sum b c)
        (+ b c))

    (sum (square x) (square y)))

Using outer symbols

(define (assert-equal a b)

    (define (print-error)
        (display a)
        (display " is not equal to ")
        (display b)
        (newline))

    (if (not (equal? a b)) (print-error) null))

> (assert-equal 3 (+ 1 2))

> (assert-equal 3 (+ 2 2))
3 is not equal to 4

Using outer symbols (2)



(define (circle-details r)
    (define pi 3.14)
    (define (area)   (round (* pi r r)))
    (define (circum) (round (* 2 pi r)))
    (list (area) (circum)))

> (circle-details 3)
(28.0 19.0)

Returning functions





(define (make-add-one)
    (define (inc x) (+ 1 x))
    inc)

Returning functions (2)

> (make-add-one)
#<procedure:inc>
> (define myfn make-add-one)

> (myfn 2)
procedure make-add-one: expects no arguments, given 1
> (define myfn (make-add-one))

> (myfn 2)
3

Closures





(define (make-add-x x)
    (define (add-x y) (+ x y))
    add-x)

Closures (2)

> (define add-3 (make-add-x 3))

> add-3
#<procedure:add-x>
> (add-3 4)
7

Uses - Holding state




(define (make-counter)
    (define value 0)
    (define (counter)
        (set! value (+ value 1))
        value)
    counter)

Uses - Holding state (2)

> (define mycounter1 (make-counter))

> (mycounter1)
1
> (mycounter1)
2
> (mycounter1)
3

Uses - Holding state (3)

> (define mycounter2 (make-counter))

> (mycounter2)
1
> (mycounter1)
4
> (mycounter2)
2
> (mycounter1)
5

Uses - Testing




(define (shout display-fn txt)
    (display-fn
        (list->string
            (map
                char-upcase
                (string->list txt)))))

Uses - Testing (2)

> (shout display "boo")
BOO

Uses - Testing (3)



(define (test-shout-displays-upper-case)
    (define displayed "")
    (define (fake-display txt)
        (set! displayed txt))

    (shout fake-display "Hello Andy")
    (assert-equal displayed "HELLO ANDY"))

Uses - Classes


(define (make-balance)
    (define value 0)
    (define (bal method)
        (define (add-method x)
            (set! value (+ value x)))
        (define (get-method) value)
        (if (equal? method "add")
            add-method
            get-method))
    bal)

Uses - Classes (2)

> (define a (make-balance))

> (a "get")
#<procedure:get-method>
> ((a "get"))
0
> ((a "add") 3)

> ((a "get"))
3

Uses - Classes (3)

> (define b (make-balance))

> ((b "get"))
0
> ((b "add") -1)

> ((b "get"))
-1
> ((a "get"))
3

Discussion