関数型言語の勉強に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!")))
今日は早めに寝ます。