SICPを読む(90) 問題3.1 - 3.4
簡単だったので、やっちまおう。
問題 3.1
アキュムレータを作れ。
(define ((make-accumulator n) x) (set! n (+ n x)) n) (define A (make-accumulator 5)) (A 10) ; 15 (A 10) ; 25
lambdaイラネー。
問題 3.2
これは面白い。関数の呼び出し回数を数える問題。
(define (make-monitored f) (let ((n 0)) (lambda x (if (equal? x '(how-many-calls?)) n (begin (set! n (+ n 1)) (apply f x)))))) (define sqrt (make-monitored sqrt)) (sqrt 4) ; 2 (sqrt 100) ; 10 (sqrt 'how-many-calls?) ; 2
関数のフックが出来るようになった。破壊的代入があるからこそ出来る。
traceとかこんな仕組みかな。再defineしなきゃいけない所が面倒そうだ。
問題 3.3
銀行口座にパスワードを設定する。
(define ((make-account balance pass) p m) (let ((withdraw (lambda (amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) (error "Insufficient funds"))))) (if (eq? pass p) (case m ('withdraw withdraw) ('deposit (lambda (x) (withdraw (- x))))) (error "Incorrect password.")))) (define tanaka (make-account 100 'himitu)) ((tanaka 'himitu 'withdraw) 40) ; 60 ((tanaka 'himitu 'deposit) 60) ; 120 ((tanaka 'hogehoge 'withdraw) 'all) ; Incorrect password.
caseを使ってみた。
問題 3.4
不正なパスワードが連続3(7だけど)回以上入力されたら、逮捕。
(define (make-account balance pass) (let ((incorrect 0)) (lambda (p m) (let ((withdraw (lambda (amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) (error "Insufficient funds"))))) (if (eq? pass p) (begin (set! incorrect 0) (case m ('withdraw withdraw) ('deposit (lambda (x) (withdraw (- x)))))) (begin (set! incorrect (+ incorrect 1)) (if (<= incorrect 3) (error "Incorrect password.") (error "逮捕します。")))))))) (define tanaka (make-account 100 'himitu)) ((tanaka 'hogehoge 'withdraw) 'all) ; Incorrect password. ((tanaka 'hogehoge 'withdraw) 'all) ; Incorrect password. ((tanaka 'hogehoge 'withdraw) 'all) ; Incorrect password. ((tanaka 'hogehoge 'withdraw) 'all) ; 逮捕します。
キャー。
まとめ
関数のフックは使えそうだ。