Scheme:named letの書き方

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))))

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の意義を教えていただけないでしょうか。

More ...