5.3.3.8
33 Solutions
This appendix contains solutions to selected exercises.
33.1 Solution: Complex, with class
This is a solution for the Complex, with class exercise.
#lang class/0 ; ========================================================== ; Complex Structure ; A Complex is a (make-complex Real Real). ; Interp: real and imaginary parts. (define-struct complex (real imag)) ; =? : Complex Complex -> Boolean ; Are the complexes equal? (check-expect (=? (make-complex 0 0) (make-complex 0 0)) true) (check-expect (=? (make-complex 0 0) (make-complex 2 3)) false) (define (=? n m) (and (= (complex-real n) (complex-real m)) (= (complex-imag n) (complex-imag m)))) ; plus : Complex Complex -> Complex ; Add the complexes. (check-expect (plus (make-complex 2 3) (make-complex 4 5)) (make-complex 6 8)) (define (plus n m) (make-complex (+ (complex-real n) (complex-real m)) (+ (complex-imag n) (complex-imag m)))) ; minus : Complex Complex -> Complex ; Subtract the complexes. (check-expect (minus (make-complex 2 3) (make-complex 4 5)) (make-complex -2 -2)) (define (minus n m) (make-complex (- (complex-real n) (complex-real m)) (- (complex-imag n) (complex-imag m)))) ; times : Complex Complex -> Complex ; Multiply the complexes. (check-expect (times (make-complex 2 3) (make-complex 4 5)) (make-complex -7 22)) (define (times n m) (make-complex (- (* (complex-real n) (complex-real m)) (* (complex-imag n) (complex-imag m))) (+ (* (complex-imag n) (complex-real m)) (* (complex-real n) (complex-imag m))))) ; div : Complex Complex -> Complex ; Divide the complexes. (check-expect (div (make-complex 2 3) (make-complex 4 5)) (make-complex 23/41 2/41)) (define (div n m) (make-complex (/ (+ (* (complex-real n) (complex-real m)) (* (complex-imag n) (complex-imag m))) (+ (sqr (complex-real m)) (sqr (complex-imag m)))) (/ (- (* (complex-imag n) (complex-real m)) (* (complex-real n) (complex-imag m))) (+ (sqr (complex-real m)) (sqr (complex-imag m)))))) ; sq : Complex -> Complex ; Multiply the complex by itself. (check-expect (sq (make-complex 0 1)) (make-complex -1 0)) (define (sq n) (times n n)) ; mag : Complex -> Number ; Compute the magnitude of the complex. (check-expect (mag (make-complex -1 0)) 1) (check-expect (mag (make-complex 3 4)) 5) (define (mag n) (sqrt (+ (sqr (complex-real n)) (sqr (complex-imag n))))) ; sqroot : Complex -> Complex ; Compute the square root of the complex. (check-expect (sqroot (make-complex -1 0)) (make-complex 0 1)) (define (sqroot n) (make-complex (sqrt (/ (+ (mag n) (complex-real n)) 2)) (* (sqrt (/ (- (mag n) (complex-real n)) 2)) (if (negative? (complex-imag n)) -1 1)))) ; to-number : Complex -> Number ; Convert the complex to a Racket complex number. (check-expect (to-number (make-complex 2 3)) 2+3i) (define (to-number n) (+ (complex-real n) (* 0+1i (complex-imag n)))) ; Alternative: ; OK, this relies on knowing about ‘make-rectangular'. ; (define (to-number n) ; (make-rectangular (complex-real n) ; (complex-imag n))) ; ========================================================== ; Complex Class ; A Complex is a (new complex% Real Real). ; Interp: real and imaginary parts. (define-class complex% (fields real imag) ; =? : Complex -> Boolean ; Is the given complex equal to this one? (check-expect (send (new complex% 0 0) =? (new complex% 0 0)) true) (check-expect (send (new complex% 0 0) =? (new complex% 2 3)) false) (define (=? n) (and (= (send this real) (send n real)) (= (send this imag) (send n imag)))) ; plus : Complex -> Complex ; Add the given complex to this one. (check-expect (send (new complex% 2 3) plus (new complex% 4 5)) (new complex% 6 8)) (define (plus n) (new complex% (+ (send this real) (send n real)) (+ (send this imag) (send n imag)))) ; minus : Complex -> Complex ; Subtract the given complex from this one. (check-expect (send (new complex% 2 3) minus (new complex% 4 5)) (new complex% -2 -2)) (define (minus n) (new complex% (- (send this real) (send n real)) (- (send this imag) (send n imag)))) ; times : Complex -> Complex ; Multiply the given complex by this one. (check-expect (send (new complex% 2 3) times (new complex% 4 5)) (new complex% -7 22)) (define (times n) (new complex% (- (* (send this real) (send n real)) (* (send this imag) (send n imag))) (+ (* (send this imag) (send n real)) (* (send this real) (send n imag))))) ; div : Complex -> Complex ; Divide this complex by the given one. (check-expect (send (new complex% 2 3) div (new complex% 4 5)) (new complex% 23/41 2/41)) (define (div n) (new complex% (/ (+ (* (send this real) (send n real)) (* (send this imag) (send n imag))) (+ (sqr (send n real)) (sqr (send n imag)))) (/ (- (* (send this imag) (send n real)) (* (send this real) (send n imag))) (+ (sqr (send n real)) (sqr (send n imag)))))) ; sq : -> Complex ; Multiply this complex by itself. (check-expect (send (new complex% 0 1) sq) (new complex% -1 0)) (define (sq) (send this times this)) ; Alternative: ; OK, but ‘this' solution is preferred. ; (define (sq) ; (times (new complex% ; (send this real) ; (send this imag)))) ; Alternative: ; Not OK: no code re-use. ; (define (times n) ; (new complex% ; (- (* (send this real) (send this real)) ; (* (send this imag) (send this imag))) ; (+ (* (send this imag) (send this real)) ; (* (send this real) (send this imag))))) ; mag : -> Number ; Compute the magnitude of this complex. (check-expect (send (new complex% -1 0) mag) 1) (check-expect (send (new complex% 3 4) mag) 5) (define (mag) (sqrt (+ (sqr (send this real)) (sqr (send this imag))))) ; sqroot : -> Complex ; Compute the square root of this complex. (check-expect (send (new complex% -1 0) sqroot) (new complex% 0 1)) (define (sqroot) (new complex% (sqrt (/ (+ (send this mag) (send this real)) 2)) (* (sqrt (/ (- (send this mag) (send this real)) 2)) (if (negative? (send this imag)) -1 1)))) ; to-number : -> Number ; Convert this complex to a Racket complex number. (check-expect (send (new complex% 2 3) to-number) 2+3i) (define (to-number) (+ (send this real) (* 0+1i (send this imag)))))
33.2 Solution: Lists of Numbers
This is a solution for the Lists of Numbers exercise.
#lang class/0 ;; ========================================================== ;; Lists of Numbers ;; INTERFACE ;; --------- ;; A ListofNumber implements: ;; ;; - length : -> Natural ;; Count the number of elements in this list. ;; ;; - append : ListofNumber -> ListofNumber ;; Append the elements of this list with the given list. ;; ;; - sum : -> Number ;; Add all the elements of this list. ;; ;; - prod : -> Number ;; Multiply all the elements of this list. ;; ;; - contains? : Number -> Boolean ;; Is the given number an element in this list? ;; ;; - reverse : -> ListofNumber ;; Reverse the elements of this list. ;; ;; - map : [Number -> Number] -> ListofNumber ;; Apply given function to each element of this list and ;; construct a list of the results ;; ;; - max-acc : Number -> Number ;; Find largest number between given and this list of numbers. ;; ;; A NeListofNumber implements ListofNumber and: ;; ;; - max : -> Number ;; Find largest number in this non-empty list. ;; IMPLEMENTATION ;; -------------- ;; A (new empty%) implements ListofNumber ;; A (new cons% Number ListofNumber) implements NeListofNumber (define-class empty% (check-expect (send mt length) 0) (define (length) 0) (check-expect (send mt append ls) ls) (define (append ls) ls) (check-expect (send mt sum) 0) (define (sum) 0) (check-expect (send mt prod) 1) (define (prod) 1) (check-expect (send mt contains? 5) false) (define (contains? n) false) (check-expect (send mt reverse) mt) (define (reverse) this) (check-expect (send mt reverse-acc ls) ls) (define (reverse-acc ls) ls) (check-expect (send mt map add1) mt) (define (map f) this) (check-expect (send mt max-acc 5) 5) (define (max-acc a) a)) (define-class cons% (fields first rest) (check-expect (send ls length) 3) (define (length) (add1 (send (send this rest) length))) (check-expect (send ls append mt) ls) (define (append ls) (new cons% (send this first) (send (send this rest) append ls))) (check-expect (send ls sum) 9) (define (sum) (+ (send this first) (send (send this rest) sum))) (check-expect (send ls prod) 24) (define (prod) (* (send this first) (send (send this rest) prod))) (check-expect (send ls contains? 5) false) (check-expect (send ls contains? 2) true) (define (contains? n) (or (= n (send this first)) (send (send this rest) contains? n))) (check-expect (send ls reverse) (new cons% 4 (new cons% 2 (new cons% 3 mt)))) (define (reverse) (reverse-acc (new empty%))) (check-expect (send ls reverse-acc ls) (new cons% 4 (new cons% 2 (new cons% 3 ls)))) ;; ACCUM: elements seen in reverse order. (define (reverse-acc ls) (send (send this rest) reverse-acc (new cons% (send this first) ls))) (check-expect (send ls map add1) (new cons% 4 (new cons% 3 (new cons% 5 mt)))) (define (map f) (new cons% (f (send this first)) (send (send this rest) map f))) (check-expect (send ls max-acc 8) 8) (check-expect (send ls max-acc 0) 4) ;; ACCUM: largest number seen so far. (define (max-acc a) (send (send this rest) max-acc (cond [(> (send this first) a) (send this first)] [else a]))) (check-expect (send ls max) 4) (define (max) (send (send this rest) max-acc (send this first)))) (define mt (new empty%)) (define ls (new cons% 3 (new cons% 2 (new cons% 4 mt))))
33.3 Solution: Home on the Range
This is a solution for the Home on the Range exercise.
#lang class/0 ; A Range is one of ; - (new range% Number Number) ; Interp: represents the range between ‘lo' and ‘hi' ; including ‘lo', but *not* including ‘hi' ; and implements IRange. ; The IRange interface includes: ; - in-range? : Number -> Boolean ; determine if the given number is in this range ; - union : Range -> Range ; produce the range containing this and the given range (define-class range% (fields lo hi) (check-expect ((range% 0 1) . in-range? 0) true) (check-expect ((range% 0 1) . in-range? 1) false) (define (in-range? n) (and (>= n (send this lo)) (< n (send this hi)))) (define (union r) (union-range% this r))) ; Part 2: ; A Range is one of ; - (new range% Number Number) ; Interp: represents the range between ‘lo' and ‘hi' ; including ‘lo', but *not* including ‘hi' ; - (new hi-range% Number Number) ; Interp: represents the range between ‘lo' and ‘hi' ; including ‘hi', but *not* including ‘lo' ; and implements IRange. (define-class hi-range% (fields lo hi) (check-expect ((hi-range% 0 1) . in-range? 0) false) (check-expect ((hi-range% 0 1) . in-range? 0.5) true) (check-expect ((hi-range% 0 1) . in-range? 1) true) (define (in-range? n) (and (> n (send this lo)) (<= n (send this hi)))) (define (union r) (union-range% this r))) ; Part 3: ; A Range is one of ; - (new range% Number Number) ; Interp: represents the range between ‘lo' and ‘hi' ; including ‘lo', but *not* including ‘hi' ; - (new hi-range% Number Number) ; Interp: represents the range between ‘lo' and ‘hi' ; including ‘hi', but *not* including ‘lo' ; - (new union-range% Range Range) ; Interp: including all the numbers in both ranges ; and implements IRange. (define-class union-range% (fields left right) (define (in-range? n) (or ((send this left) . in-range? n) ((send this right) . in-range? n))) (define (union r) (union-range% this r))) (define r1 (range% 0 1)) (define r2 (hi-range% 0 1)) (define r3 (range% 2 4)) ; union + in-range? test (check-expect (r1 . union r2 . union r3 . in-range? 3) true) ; testing all the union methods (check-expect (r1 . union r2 . in-range? 1) true) (check-expect (r2 . union r1 . in-range? 0) true)
33.4 Solution: Zombie!
This is a solution for the Zombie! exercise.
#lang class/0 (require 2htdp/image) (require class/universe) ; A Zombie is one of: ; - Undead ; - Dead ; implements Point and: ; - move-toward : Player -> Zombie ; - eat-zombie-brains? : Zombie -> Boolean ; - eat-player-brains? : Player -> Boolean ; - draw-on : Scene -> Scene ; A Undead is a (new undead% ...) ; A Dead is a (new dead% ...) ; A Zombies is one of: ; - (new emptyz%) ; - (new conz% Zombie Zombies) ; implements ; - draw-on : Scene -> Scene ; A Player is (new player% Posn) ; implements Point and ; - move-toward : Mouse -> Player ; - draw-on : Scene -> Scene ; A Point implements ; - x : -> Number ; - y : -> Number ; A Posn is a (new posn% Number Number) ; implements Point and ; - move-toward : Point -> Posn ; - draw-on/image : Image Scene -> Scene ; A Mouse is a (new mouse% Number Number) ; implements ; draw-on : Scene -> Scene ; Draws this mouse on the scene (define PLAYER-VELOCITY 3) (define ZOMBIE-VELOCITY 1) (define PLAYER-RADIUS 10) (define ZOMBIE-RADIUS 10) (define-class emptyz% (define (draw-on scn) scn) (define (move-toward player) this) (define (any-eating-player-brains? player) false) (define (any-eating-zombie-brains? zombie) false) (define (kill-any-touching) this) (define (kill-any-touching/a zs) zs)) (define-class conz% (fields first rest) (define (draw-on scn) (send (send this first) draw-on (send (send this rest) draw-on scn))) (define (move-toward player) (new conz% (send (send this first) move-toward player) (send (send this rest) move-toward player))) (define (any-eating-player-brains? player) (or (send (send this first) eat-player-brains? player) (send (send this rest) any-eating-player-brains? player))) (define (any-eating-zombie-brains? zombie) (or (send (send this first) eat-zombie-brains? zombie) (send (send this rest) any-eating-zombie-brains? zombie))) (define (kill-any-touching) (send this kill-any-touching/a (new emptyz%))) (define (kill-any-touching/a zs) (local [(define first-z (send this first)) (define rest-z (send this rest))] (cond [(or (send zs any-eating-zombie-brains? first-z) (send rest-z any-eating-zombie-brains? first-z)) (send rest-z kill-any-touching/a (new conz% (send first-z kill) zs))] [else (send rest-z kill-any-touching/a (new conz% first-z zs))])))) ; A Undead is a (new undead% Posn) implements Zombie (define-class undead% (fields p) ; - move-toward : Player -> Zombie ; - eat-zombie-brains? : Zombie -> Boolean ; - eat-player-brains? : Player -> Boolean (define (x) (send (send this p) x)) (define (y) (send (send this p) y)) (check-expect (send (new undead% (new posn% 10 20)) draw-on (empty-scene 100 100)) (place-image (circle ZOMBIE-RADIUS "solid" "red") 10 20 (empty-scene 100 100))) (define (draw-on scn) (send (send this p) draw-on/image (circle ZOMBIE-RADIUS "solid" "red") scn)) (check-expect (send (new undead% (new posn% 0 0)) move-toward (new player% (new posn% 0 10))) (new undead% (new posn% 0 ZOMBIE-VELOCITY))) (check-expect (send (new undead% (new posn% 0 0)) move-toward (new player% (new posn% 10 0))) (new undead% (new posn% ZOMBIE-VELOCITY 0))) ; move-toward : Player -> Zombie ; Move this player ZOMBIE-VELOCITY units toward the given player. (define (move-toward player) (new undead% (send (send this p) move-toward player ZOMBIE-VELOCITY))) ; eat-player-brains? : Player -> Boolean (define (eat-player-brains? player) (< (send (send this p) dist player) (+ ZOMBIE-RADIUS PLAYER-RADIUS))) ; eat-zombie-brains? : Zombie -> Boolean (define (eat-zombie-brains? zombie) (< (send (send this p) dist zombie) (* 2 ZOMBIE-RADIUS))) ; kill : -> Dead (define (kill) (new dead% (send this p)))) ; A Dead is a (new dead% ...) implements Zombie (define-class dead% (fields p) (define (x) (send (send this p) x)) (define (y) (send (send this p) y)) ; - move-toward : Player -> Zombie ; - eat-zombie-brains? : Zombie -> Boolean ; - eat-player-brains? : Player -> Boolean (check-expect (send (new dead% (new posn% 10 20)) draw-on (empty-scene 100 100)) (place-image (circle ZOMBIE-RADIUS "solid" "gray") 10 20 (empty-scene 100 100))) (define (draw-on scn) (send (send this p) draw-on/image (circle ZOMBIE-RADIUS "solid" "gray") scn)) (check-expect (send (new dead% (new posn% 0 0)) move-toward (new player% (new posn% 0 10))) (new dead% (new posn% 0 0))) (check-expect (send (new dead% (new posn% 0 0)) move-toward (new player% (new posn% 10 0))) (new dead% (new posn% 0 0))) (define (move-toward player) this) ; eat-player-brains? : Player -> Boolean (define (eat-player-brains? player) (< (send (send this p) dist player) (+ ZOMBIE-RADIUS PLAYER-RADIUS))) ; eat-zombie-brains? : Zombie -> Boolean (define (eat-zombie-brains? zombie) (< (send (send this p) dist zombie) (* 2 ZOMBIE-RADIUS))) ; kill : -> Dead (define (kill) this)) (define-class posn% (fields x y) ; Move this position toward that one at given velocity. ; move-toward : Point Number -> Posn (define (move-toward that velocity) (local [(define delta-x (- (send that x) (send this x))) (define delta-y (- (send that y) (send this y))) (define move-distance (min velocity (max (abs delta-x) (abs delta-y))))] (cond [(< (abs delta-x) (abs delta-y)) ; move along y-axis (cond [(positive? delta-y) (send this move 0 move-distance)] [else (send this move 0 (- move-distance))])] [else ; move along x-axis (cond [(positive? delta-x) (send this move move-distance 0)] [else (send this move (- move-distance) 0)])]))) ; move : Number Number -> Posn (define (move delta-x delta-y) (new posn% (+ (send this x) delta-x) (+ (send this y) delta-y))) ; draw-on/image : Image Scene -> Scene (define (draw-on/image img scn) (place-image img (send this x) (send this y) scn)) ; dist : Point -> Number ; Compute the distance between this posn and that point. (define (dist that) (sqrt (+ (sqr (- (send that y) (send this y))) (sqr (- (send that x) (send this x))))))) (define-class player% (fields p) (define (x) (send (send this p) x)) (define (y) (send (send this p) y)) ; move-toward : Mouse -> Player ; Move this player PLAYER-VELOCITY units toward the given mouse. (define (move-toward mouse) (new player% (send (send this p) move-toward mouse PLAYER-VELOCITY))) (check-expect (send (new player% (new posn% 10 20)) draw-on (empty-scene 100 100)) (place-image (circle PLAYER-RADIUS "solid" "green") 10 20 (empty-scene 100 100))) (define (draw-on scn) (send (send this p) draw-on/image (circle PLAYER-RADIUS "solid" "green") scn))) (check-expect (send (new posn% 0 0) move-toward (new posn% 0 0) 100) (new posn% 0 0)) (check-expect (send (new posn% 0 0) move-toward (new posn% 100 0) 50) (new posn% 50 0)) (check-expect (send (new posn% 0 0) move-toward (new posn% 0 100) 50) (new posn% 0 50)) (check-expect (send (new posn% 0 0) move-toward (new posn% 100 100) 50) (new posn% 50 0)) (check-expect (send (new posn% 0 0) move-toward (new posn% 100 101) 50) (new posn% 0 50)) (check-expect (send (new posn% 0 0) move-toward (new posn% 101 100) 50) (new posn% 50 0)) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 0 0)) (new player% (new posn% 0 0))) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 100 0)) (new player% (new posn% PLAYER-VELOCITY 0))) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 0 100)) (new player% (new posn% 0 PLAYER-VELOCITY))) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 100 100)) (new player% (new posn% PLAYER-VELOCITY 0))) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 100 101)) (new player% (new posn% 0 PLAYER-VELOCITY))) (check-expect (send (new player% (new posn% 0 0)) move-toward (new mouse% 101 100)) (new player% (new posn% PLAYER-VELOCITY 0))) (define-class mouse% (fields x y) ; draw-on : Scene -> Scene ; Draw this mouse on the scene (check-expect (send (new mouse% 10 20) draw-on (empty-scene 100 100)) (place-image (square 5 "solid" "red") 10 20 (empty-scene 100 100))) (define (draw-on scn) (place-image (square 5 "solid" "red") (send this x) (send this y) scn))) ; A ZombieApocalypse (ZA) is a (new za% Zombies Player Mouse) ; implements ; - on-tick : -> ZA ; - to-draw : -> Scene ; - on-mouse : MouseEvent Number Number -> ZA ; - stop-when : -> Boolean (define WIDTH 200) (define HEIGHT 200) (define-class za% (fields zombies player mouse) ; on-tick : -> ZA (define (on-tick) (new za% (send (send (send this zombies) kill-any-touching) move-toward (send this player)) (send (send this player) move-toward (send this mouse)) (send this mouse))) ; to-draw : -> Scene (define (to-draw) (send (send this zombies) draw-on (send (send this player) draw-on (send (send this mouse) draw-on (empty-scene WIDTH HEIGHT))))) ; on-mouse : Number Number MouseEvent -> ZA (define (on-mouse mx my me) (new za% (send this zombies) (send this player) (new mouse% mx my))) ; stop-when : -> Boolean (define (stop-when) (send (send this zombies) any-eating-player-brains? (send this player)))) (define world0 (new za% (new conz% (new undead% (new posn% 60 60)) (new conz% (new undead% (new posn% 100 100)) (new emptyz%))) (new player% (new posn% 0 0)) (new mouse% 0 0)))
33.5 Solution: Parametric Lists
This is a solution for the Parametric Lists exercise.
#lang class/0 ;; ========================================================== ;; Lists of X ;; INTERFACE ;; --------- ;; A [List X] implements: ;; ;; - cons : X -> [List X] ;; Cons given value on to this list. ;; ;; - length : -> Natural ;; Count the number of elements in this list. ;; ;; - append : [List X] -> [List X] ;; Append the elements of this list with the given list. ;; ;; - reverse : -> [List X] ;; Reverse the elements of this list. ;; ;; - map [Y] : [X -> Y] -> [List Y] ;; Apply given function to each element of this list and ;; construct a list of the results ;; ;; - filter : [X -> Boolean] -> [List X] ;; Select elements that satisfy the given predicate. ;; ;; - foldr [Y] : [X Y -> Y] Y -> Y ;; Fold right over this list. ;; ;; - foldl [Y] : [X Y -> Y] Y -> Y ;; Fold left over this list. ;; A [Cons X] implements [List X] and: ;; ;; - first : -> X ;; Get first element of this non-empty list. ;; ;; - rest : -> [List X] ;; Get the reset of this non-empty list. ;; IMPLEMENTATION ;; -------------- ;; A (new empty%) implements [List X] ;; A (new cons% X [Listof X]) implements [Cons X] (define-class empty% (check-expect (send mt cons 0) (new cons% 0 mt)) (define (cons x) (new cons% x this)) (check-expect (send mt length) 0) (define (length) 0) (check-expect (send mt append ls) ls) (define (append ls) ls) (check-expect (send mt reverse) mt) (define (reverse) this) (check-expect (send mt reverse-acc ls) ls) (define (reverse-acc ls) ls) (check-expect (send mt map add1) mt) (define (map f) this) (check-expect (send mt foldr + 0) 0) (define (foldr f b) b) (check-expect (send mt foldl + 0) 0) (define (foldl f b) b)) (define-class cons% (fields first rest) (check-expect (send ls cons 0) (new cons% 0 ls)) (define (cons x) (new cons% x this)) (check-expect (send ls length) 3) (define (length) (add1 (send (send this rest) length))) (check-expect (send ls append mt) ls) (define (append ls) (new cons% (send this first) (send (send this rest) append ls))) (check-expect (send ls reverse) (new cons% 4 (new cons% 2 (new cons% 3 mt)))) (define (reverse) (reverse-acc (new empty%))) (check-expect (send ls reverse-acc ls) (new cons% 4 (new cons% 2 (new cons% 3 ls)))) ;; ACCUM: elements seen in reverse order. (define (reverse-acc ls) (send (send this rest) reverse-acc (new cons% (send this first) ls))) (check-expect (send ls map add1) (new cons% 4 (new cons% 3 (new cons% 5 mt)))) (define (map f) (new cons% (f (send this first)) (send (send this rest) map f))) (check-expect (send ls foldr + 0) 9) (define (foldr f b) (f (this . first) (this . rest . foldr f b))) (check-expect (send ls foldl + 0) 9) (define (foldl f b) (this . rest . foldl f (f (this . first) b)))) (define mt (new empty%)) (define ls (new cons% 3 (new cons% 2 (new cons% 4 mt))))
33.6 Solution: Shapes
This is a solution for the Shapes exercise.
#lang class/1 ;; Solution to part 1. #; (define-class rect% (fields width height) (define (bba) (* (this . width) (this . height)))) #; (define-class circ% (fields radius) (define (bba) (sqr (* 2 (this . radius))))) ;; A Shape implements: ;; width : -> Number ;; height : -> Number ;; Compute the {width,height} of this shape. ;; Solution to part 2. (define-class shape% (define (bba) (* (this . width) (this . height)))) (define-class rect% (super shape%) (fields width height)) (define-class circ% (super shape%) (fields radius) (define (width) (* 2 (this . radius))) (define (height) (this . width))) ;; Solution to part 3. (define-class square% (super shape%) (fields width) (define (height) (this . width))) (check-expect ((new rect% 3 4) . bba) 12) (check-expect ((new circ% 1.5) . bba) 9) (check-expect ((new square% 5) . bba) 25)
33.7 Solution: Abstract Lists
This is a solution for the Abstract Lists exercise.
#lang class/1 ;; ========================================================== ;; Lists of X with inheritance ;; IMPLEMENTATION ;; -------------- ;; A (new empty%) implements [List X], extends list% ;; A (new cons% X [Listof X]) implements [Cons X], extends list% (define-class list% (check-expect (send mt empty) mt) (check-expect (send ls empty) mt) (define (empty) (new empty%)) (check-expect (send mt cons 0) (new cons% 0 mt)) (define (cons x) (new cons% x this)) (check-expect (send mt length) 0) (check-expect (send ls length) 3) (define (length) (send this foldl (λ (x len) (add1 len)) 0)) (check-expect (send mt append ls) ls) (check-expect (send ls append mt) ls) (define (append ls) (send this foldr (λ (x ls) (ls . cons x)) ls)) (check-expect (send mt reverse) mt) (check-expect (send ls reverse) (new cons% 4 (new cons% 2 (new cons% 3 mt)))) (define (reverse) (send this foldl (λ (x ls) (ls . cons x)) (this . empty))) (check-expect (send mt map add1) mt) (check-expect (send ls map add1) (new cons% 4 (new cons% 3 (new cons% 5 mt)))) (define (map f) (send this foldr (λ (x ys) (ys . cons (f x))) (this . empty)))) (define-class empty% (super list%) (check-expect (send mt foldr + 0) 0) (define (foldr f b) b) (check-expect (send mt foldl + 0) 0) (define (foldl f b) b)) (define-class cons% (super list%) (fields first rest) (check-expect (send ls foldr + 0) 9) (define (foldr f b) (f (this . first) (this . rest . foldr f b))) (check-expect (send ls foldl + 0) 9) (define (foldl f b) (this . rest . foldl f (f (this . first) b)))) (define mt (new empty%)) (define ls (new cons% 3 (new cons% 2 (new cons% 4 mt))))
33.8 Solution: Functional programming with objects
This is a solution for the Functional programming with objects exercise.
#lang class/1 ;; A [IFun X Y] implements: ;; - apply : X -> Y ;; Apply this function to the given input. ;; - compose : [IFun Y Z] -> [IFun X Z] ;; Produce a function that applies this function to its input, ;; then applies the given function to that result. ;; A (new fun% [X -> Y]) implements [IFun X Y]. (define-class fun% (fields f) (define (apply x) ((this . f) x)) (define (compose g) (new fun% (λ (x) (g . apply (this . apply x)))))) (define addone (new fun% add1)) (define subone (new fun% sub1)) (check-expect ((addone . compose subone) . apply 5) 5) (check-expect ((addone . compose addone) . apply 5) 7)