関数型言語の勉強にSICPを読もう - (36) 3章 - 小休止 port-foreach

Ruiさんよりコメントを頂きました。
Schemeに慣れた人が書くとこんなにもきれいなのか。ありがとうございます。
このようにコードを見せていただくことはとても勉強になります。

sum は (apply + list) と書けますね。Gaucheだとport-for-eachという便利な高階手続きがあって、それをつかうと全体は次のようになります。(一時ファイルを使わないで済むよう、call-with-input-fileの代わりにcall-with-input-stringを使いました。)

たしかに、sum は (apply + list)ですね。何で気づかなかったんだろう。

 (port-for-each (lambda (list)
                  (print (apply + list)))
                (call-with-input-string ”(1 2 3) (4 5 6)”
                  (lambda (in)
                    (lambda () (read in)))))

port-for-eachは、2番目の引数の手続きがeofオブジェクトを返すまで繰り返し呼び出して、1番目の引数の手続きにその値を渡す手続きです。こういった高階手続きをうまく使うと自分でループを回す必要が減ってプログラムが簡潔になります。


ぱっと見ると分からないので分解してみましょう。

(port-foreach 手続きA 手続きB)

という構造です。
手続きAは手続きBが eof まで返しつづける値を引数として受け取り何らかの処理を行います。
実は手続きBは port に絡まなくてもいつか eof を返せばよいらしいです。


次は、手続きBにあたる call-with-input-stringですが、これは文字列を第一引数とてして受け取ります。
これが input の port となって 第2引数の手続きが呼ばれます。
さらに第2引数が「 read をして eof を返す」手続きを返します。(うわこれSchemeっぽい)


というわけで一応理解できたつもりですが、自分で一から書けるかというとかなり不安なので何かしらの練習問題をやったほうがよさそう。



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


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