関数型言語の勉強にSICPを読もう - (65) 4章 - 超言語的抽象(222ページ) C++でSchemeインタプリタを作ろう14

問題4.5

  (display (cond (1 => plus5))))

これを評価すると 6 が表示されます。
この形式の cond をサポートせよという問題。


昨日、この構文が美しくないなあとぼやいたら shiro さんからコメントを頂きました。

(cond (x => a)) はですね。xの評価結果が#fでない場合にその値を後の処理で使いたい、
という時に便利なのです。例:

(cond ((string->number s) => proc)
(else (error ”bad input:” s)))

string->number は引数が数値と解釈できる文字列ならその数値を、そうでなければ#fを
返すので、上のコードで不正な入力をはじくことができます。=> が無いなら一度一時変数
で受けないとなりません:

(let ((tmp (string->number s)))
(if tmp (proc tmp) (error ...)))

でも、何で関数呼出なの? って思うかもしれません。condの中で結果を受けるローカル
変数を指定できるようにしておいてもいいんじゃない、ってね。

その答えは、Schemerにとってローカル変数は関数呼出しのシンタックスシュガーに
すぎないからです。

なるほど。とても詳しいコメントをありがとうございます。
使い方の実例を見ると確かにかっこよく見えてきました。


さて実装ですが、問題を見た時点では「Condクラスを拡張してこの構文も受け入れられるようにしよう」とかうっすらと考えていました。
しかし昨日寝床で思い付きました。
(cond (1 => plus5))は(cond (1 (plus5 1))と(多分)等価なので、Translator(構文木からオブジェクトを生成する部分)で既にサポート済な等価な構文としてオブジェクトを生成してやれば良さそう。
実際やってみたらうまくいきました。これでソースが汚くなりそうな危機を乗り越えられました。


テストのために display/number?/string?/string->numberなどの primitive procedureも追加しました。
これが正しく動いています。

(begin
  (define plus3display (lambda (x) (display (+ x 3))))
  (define value "100")
  (cond ((string->number value) => plus3display)
        (display "not number!")))


今日は早めに寝ます。


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


計算機プログラムの構造と解釈
ジェラルド・ジェイ サスマン ジュリー サスマン ハロルド エイブルソン 和田 英一
ピアソンエデュケーション (2000/02)
売り上げランキング: 56,404