LoginSignup
0
0

More than 3 years have passed since last update.

SICP読書録 #27 練習問題2.37 - 練習問題2.39

Posted at

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-leftfold-rightが同じ結果となるためには、渡す手続きが交換則を満たす必要がある。

練習問題 2.39

fold-rightfold-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))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0