理系学生日記

おまえはいつまで学生気分なのか

問題2-33 (2.2.3 Sequences as Conventional Interfaces)

この小節(2.2.3)では、モジュールの構成法、可読性のためにとても大事なことを言っていて、いわく信号処理のように、独立したブロックとして考えなさいって言っている。
プログラムを組むときには当たり前の話ですけど、副作用のない関数型言語であれば、かなり厳密に守れるのかもしれません。
今日の課題はその構成要素となれるのを組むこと。

(define (accumulate op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
	  (accumulate op initial (cdr sequence)))))

accumulateを使って、まずmapを作る。mapはリストの各要素に対して関数を適用した結果を返す関数です。たいていの言語には用意されてて、gaucheにも用意されているけど、自作するみたい。

(define (map p sequence)
  (accumulate (lambda (x y)
		(cons (p x) y))
	      ()
	      sequence))

こんな感じの関数です。

gosh> (map square (list 1 2 3 4 5))
(1 4 9 16 25)

appendは2つのリストを連結します。

(define (append seq1 seq2)
  (accumulate cons seq2 seq1))

すげーすっきりしてる。こんな感じの実行結果ですね。

gosh> (append (list 1 2 3) (list 4 5 6))
(1 2 3 4 5 6)

lengthはリストの長さを返すシンプルな関数ですけど、他に比べるとちょびっと複雑になった。

(define (length sequence)
  (accumulate (lambda (x y)
		(if (null? x)
		    (+ 0 y)
		    (+ 1 y)))
	      0
	      sequence))

こうなります。

gosh> (length (list 1 2 3 4))
4