Scheme:named letの書き方
(Scheme:初心者の質問箱より移動)
named letでループを書くと、次のようなコードによくなります。
(let loop ((ch (read-char in))) (cond ((eof-object? ch) ...) (else ... (loop (read-char in)))))
ここで、read-charが2度現れているのがうれしくない。たいてい同じ引数で同じ手続きを呼んでいて、なんだか冗長です。たとえばread-charをread-byteに変更したくなったら2箇所変えないといけない。とはいえ、次のようにするのもそれはそれで普通ではない感じがするので、上のような書き方はしかたないんですかねえ。
(let loop () (let ((ch (read-char in))) (cond ((eof-object? ch) ...) (else ... (loop))))
- び: 最初のread-charのところが初期化、最後の再起呼び出しのところのread-charがステップというイメージなので特に違和感はありませんが、「初期化とステップは同じ処理だよ」と強調したいときは次のように書いたりします。本質的な違いはないですけども。
(let1 proc (lambda () (read-char in)) (let loop ((ch (proc))) (cond ((eof-object? ch) ...) (else ... (loop (proc))))))
- このやり方は lexer 書くときは C でありがちな ungetc が出てきづらくなるので一般的にはうれしいのだけど、上の例に限っては port-for-each なんてのもあります。
Shiro(2005/09/12 02:55:56 PDT): まあ、もっともな疑問です。私も普通は最初の方式で書きますが、 分岐の先で何度も(read-char)が出てきてちょっと危険な香りを感じると2番目の方法 (ループ内でletを使ってchを束縛)にすることもあります。
Cでforループを書く時も同じようなジレンマがありますよね。まあこの例に関しては while文の条件式の中でgetchar()とEOF判定が出来てしまうので普通はそっちを 使いますが、判定が単純でない場合なんかはちょっと迷うこともあります。
たまには日陰者のdoなど如何?さらに見た目が怪しい感じですが(笑
(do ((ch (read-char in) (read-char in))) ((eof-object? ch) ...) ...)
Shiro: 日陰者といえば、Gaucheにはずっとundocumentedな地位に甘んじていた while, untilというマクロがあったんですが、0.8.6から晴れて正式なマクロに 昇格します。アクションと条件が別々に書けるようになって、さらに束縛もできるように なったんで、上のパターンはこんなふうに書けます。お薦めするわけじゃありませんが…
(until (read-char in) eof-object? => ch ...)
CVS HEADのuntilの定義で`=>'がシンタックスルールになっていません。
Shiro: おっありがとう。直しました。
student:初学者ですが、schemeのおもしろさにはまっています。schemeレベル1というところでしょうか。さて、いま末尾再帰と名前付きletを勉強していますが、すべて末尾再帰だけで書くことは不可能なのでしょうか?なんとなく名前付きletは構文が複雑すぎてうさんくさく感じてしまい.. ちょっと場違いかもしれませんが、名前付きletの意義を教えていただけないでしょうか。
- 末尾再帰で書くというのは、named letと同じことをlambdaだけで書くということを意味していると思いますが、もちろん可能です。Schemeでは、変数を束縛する構文(let, letrec, recなどいろいろ)は、すべてlambda式で書くことができます。named letをマクロで展開して、等価なlambda式に置き換えることができます。例は R5RSを見てください。実際の実装では、効率などの事情でletを組み込みの構文にしているものが多いと思いますが、lambdaだけをプリミティブな構文にして、それ以外の構文はlambdaに展開する実装も可能です。私はnamed letを複雑だと感じません。結局はlambdaを書きやすくしているだけだとわかれば気持ち悪さもなくなると思いますよ。
- ご回答ありがとうございました。おっしゃってる内容を全部は正確には理解できないのですが、意味する方向性はわかるような気がします。末尾再帰と同様に名前付きletの構文のほうでも車輪の再生産にはげんでみます。