hiroshi-manabe様の日本語訳を使わせてもらいます。
練習問題等はGaucheで実行。
練習問題 2.37
リストのリストで行列を表すことができる。例えば以下の行列は、
\begin{pmatrix}
1 & 2 & 3 & 4 \\
4 & 5 & 6 & 6 \\
6 & 7 & 8 & 9
\end{pmatrix}
((1 2 3 4) (4 5 6 6) (6 7 8 9))
という式で表す。
行列を表せるようになったんだから、行列に対する各種の操作を行うための手続きを作ろう。
まずは内積。
_.scm
(define (dot-product v w)
(accumulate + 0 (map * v w)))
行列とベクトルの積。
_.scm
(define (matrix-*-vector m v)
(map (lambda (r) (dot-product r v)) m))
転置行列。
_.scm
(define (transpose mat)
(accumulate-n cons nil mat))
行列どうしの積。
_.scm
(define (matrix-*-matrix m n)
(let ((cols (transpose n)))
(map (lambda (r) (matrix-*-vector cols r)) m)))
練習問題 2.38
accumulate
は、列の最初の要素と、右のすべての要素を組み合わせた結果、を組み合わせる手続きなのだから、fold-right
と名付けてみよう。
_.scm
(define fold-right accumulate)
逆方向に組み合わせを行うfold-left
手続きを以下のように定義する。
_.scm
(define (fold-left op initial sequence)
(define (iter result rest)
(if (null? rest)
result
(iter (op result (car rest))
(cdr rest))))
(iter initial sequence))
それぞれ実行してみる。
_.scm
gosh> (fold-right / 1 '(1 2 3))
3/2
gosh> (fold-left / 1 '(1 2 3))
1/6
と、このように結果が異なる。
fold-right
は(/ 1 (/ 2 3))
という計算を行っていて、
fold-left
は(/ (/ 1 2) 3)
という計算を行っているためだ。
もうひとつ実行例。
_.scm
gosh> (fold-right list nil '(1 2 3))
(1 (2 (3 ())))
gosh> (fold-left list nil '(1 2 3))
(((() 1) 2) 3)
fold-left
とfold-right
が同じ結果となるためには、渡す手続きが交換則を満たす必要がある。
練習問題 2.39
fold-right
とfold-left
をそれぞれ使って、リストの要素を逆順にして返すreverse
手続きを作ってみよう。
_.scm
(define (reverse1 sequence)
(fold-right (lambda (x y) (append y (list x))) nil sequence))
(define (reverse2 sequence)
(fold-left (lambda (x y) (cons y x)) nil sequence))