関数型言語の勉強にSICPを読もう - (8) 1章 - 手続きによる抽象の構築(31-44ページ)

1.3 高階手続き

やっとここまでたどり着いた。
概念は理解しているし、たまに使うけど何か発見があるのではないだろうか。

問題1.31

(define (product term a next b)
  (if (> a b)
      1
      (* (term a)
         (product term (next a) next b))))

(define (factorial n)
  (define (next n)
    (+ n 1))
  (define (term n)
    n)
  (product term 1 next n))

これは再帰的プロセス。
反復的プロセスが苦手だ。
考えてみよう。

反復的プロセスは、状態保持のために引数が増えていて、途中経過は常に引数にわたってくる。
そのため、再帰的プロセスと違いスタック的データ構造に状態保持をしなくて良い。
という理解でよいだろうか?
結局答えを見てしまった。

(define (product term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (* (term a) result))))
  (iter a 1))

問題1.32

更にもう一段抽象化する。
楽しくなってきた。

(define (accumulate combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (term a)
                (accumulate combiner null-value term (next a) next b))))

(define (product term a next b)
  (define (multiply x y)
    (* x y))
  (accumulate multiply 1 term a next b))

34ページ

あっさりlambda式の説明が終わる。
でも、納得・理解しているので問題ないと思う。
注釈のlambdaの名前についての話が面白い。

36ページ

lambda式で

(define (f x y)
  ((lambda (a b)
     (+ (* x (square a))
        (* y b)
        (* a b)))
   (+ 1 (* x y))
   (- 1 y)))

これが一瞬分からなかった。
無名関数に引数をその場で渡している感じなのか。ふむふむ。
letはこれのシンタックスシュガーとのこと。
まだ頭の中でつながっていないけど言わんとすることは分かる。

だんだんとサンプルをきちんと打ち込まないと理解できないようになって来た。

(define x 5)
(+ (let ((x 3))
     (+ x (* x 10)))
   x)

これが38になるというのがぱっと分からない。

あぁこれは束縛の話か。
つまり

(+ (+ 3 (* 3 10)
   5)

ということ。

37ページ

区間二分法。また数学か!と身構えたが簡単だった。

41ページ

値として返される手続き。
次のステップだ。
例が難しいよ。数学的要素が少なければもっと分かりやすいのに。

43ページ

良い言葉発見
「われわれはプログラマとしてプログラムの根底にある抽象を見つけ、より強力な抽象化ができるよう、その上に構成し一般化するよう努めなければならない。
これはプログラムを可能な限り抽象的に書くべしというのではない。経験をつんだプログラマは自分の仕事に適した抽象のレベルを選ぶことを知っている。」

問題1.41

楽しくなってきた。

(define (double f)
  (lambda (x)
     (f (f x))
     ))
   
((double square) 2)

問題1.42

(define (compose f g)
  (lambda (x)
    (f (g x))))


※「SICPを読もう」の目次はこちら


計算機プログラムの構造と解釈
Gerald Jay Sussman Julie Sussman Harold Abelson 和田 英一
ピアソンエデュケーション (2000/02)
売り上げランキング: 56,404