議事録(第四回目)

木曜日の勉強会では、第一章の第三節に入りました。今回は僕が勉強会の進行役を務めましたが、まだまだ理解度が足りていない部分については、案の定上手いこと説明することができませんでした。しかし、事前に練習問題をやってから勉強会に臨むというのは初めてのケースだったので、その点については良かったなと思っています。前回のエントリーで書いた自分の疑問点を解消することができたので、今日はそのことについてメモを残しておきます。
まずは、問題1-32のcombinerについてです。渡された引数の値をどのように処理するかという具体的な手続きで、もっと上手い書き方があるのではと思っていましたが、やはりありました。例えば、引数の値を加算するような手続きを渡すためには、

(define (sum term a next b)
  (define (combiner x y)
    (+ x y))
  (accumulate combiner 0 term a next b))

のように表現しなければならないと思い込んでいましたが、こんなことをする必要はなく、

(define (sum term a next b)
  (accumulate + 0 term a next b))

このように「+」を渡してやればいいということがわかりました。まだまだ四則演算の記号を特殊なものとしてみている証拠です。このあたりの先入観については、早いところ取っ払っていかなければならないなと感じました。
次が、問題1-33のfilterについてで、ローカル変数・束縛変数の理解の甘さを痛感しました。本質的には一つしか必要のないfilter手続きの引数ですが、問題bの方では二つにしないと必要なデータを使うことができないと思ったため、しっくりこないコードを書いてしまいました。どうやら、メインの手続きと、具体的なfilter手続きを別々に定義してしまったために、データを上手いこと使うことができなかったようです。

(define (gcd-filter tgt to)
  (= (gcd tgt to) 1))

(define (gcd-product to)
  (filtered-product gcd-filter identity 1 inc to))

このfilter手続きをメイン手続きの中に入れてしまえば、filter手続きの引数はtgtだけで済みます。(終着点であるtoは処理を通じて変化しないので、メイン手続きの中で束縛されるようにしてやればいいということになります。)

(define (gcd-product to)
  (define (gcd-filter tgt)
    (= (gcd tgt to) 1))
  (filtered-product gcd-filter identity 1 inc to))

このあたりのことを抑えておかないと、lambdaやletを使うケースではより混乱してしまうだろうという指摘もあったので、注意していきたいと思います。