SICPを読む(97) 問題 3.8 - 命令プログラミングの落とし穴

問題を読み取れているのかわからない。

問題 3.8

最初に関数が呼ばれたのであれば、その値を返す。二度目以降なら0を返す。という関数にしてみた。

(define f
  (let ((flag #f))
       (lambda (n)
         (if flag
             0
             (begin (set! flag #t) n)))))

フラグが立っていなければ、値を返し、フラグが立っていたらゼロを返す。

右から評価が出来ないので、fを入れ替えてテストした。

(+ (f 0) (f 1)) ; 0
; fを再定義
(+ (f 1) (f 0)) ; 1

SICPと問題共有できてるのかな・・・。


回答を探索してみると色々あって面白い。

  • 掛け算法
    • 初期値を1として前回のと掛け算。
    • 1 * 0 + 0 * 1 = 0, 1 * 1 + 1 * 0
    • なるほど。うまいな。
  • 前回の値を返す
    • 初期値を0としておいて、
    • (f 0) + (f 1) = 0 + 0, (f 1) + (f 0) = 0 + 1
    • うまくいく。

色々解釈できるようだ。


足し算の方は遅延評価を使って評価を遅らせる方法もあると。

やってみよう。

(define (my-apply f method . args)
  (apply f (map (lambda (f) (f))
                (if (eq? method 'reverse)
                    (reverse args)
                    args))))

; リセットして 
(my-apply + 'normal (lambda () (f 0)) (lambda () (f 1))) ; 0
; リセットして
(my-apply + 'reverse (lambda () (f 0)) (lambda () (f 1))) ; 1 

delayは使わず、lambdaで実装してみた。遅延評価とか理解してないけど、lambdaで囲めば評価を遅らせることが出来るよね。