2006年06月17日

let, let*, letrec (変数束縛、バインディング構成手続き、バインディング作成手続き)

変数をその値に束縛して、ボディを評価します。
つまりlet達のボディで利用する、ローカル変数が使えるって事ですか?
手続きに束縛されているローカル変数もですね。<- 何が言いたいかというと「ローカル関数(手続き)も使える」と思ったのですが、変数が手続きに束縛されていればもちろんその手続きも利用できるのですね。

<バインディング>は((<変数1> <初期値1>) (<変数2> <初期値2>)...)

(let <バインディング> <ボディ>)
変数のバインディングが行なわれる以前に、初期値が計算されます。
つまり最初に初期値を評価してしまうので、
((変数1 初期値1) (変数2 初期値2))
の時、初期値2を評価する時には、変数1のバインディングは見られないわけですね。
(let ((x 1) (y 2)) (+ x y)) -> 3
(define x 10) -> 10
(
let (
(x 1) ;<- ローカルな x に 1
(y x) ;<- ローカルな y にグローバルな x = 10
)
(+ x y)
) -> 11 ;


(let* <バインディング> <ボディ>)
バインディングと評価が順次的に行なわれます。
つまり書いてある順番に評価されるので、
((変数1 初期値1) (変数2 初期値2))
の時、変数1のバインディング、初期値1の評価が行われた後になるので、初期値2を評価する時には、変数1のバインディングを見ることができるのですね。
(let ((x 1) (y 2)) (+ x y)) -> 3
(define x 10) -> 10
(let (
(x 1) ;<- ローカルな x に 1
(y x) ;<- ローカルな y にローカルな x = 1
)
(+ x y)
) -> 2 ;



(letrec <バインディング> <ボディ>)
初期値が計算されている間にもバインディングが有効であり、したがって相互に再帰的な定義が可能です。<- 意味がわかりません。
最初にバインディングが行われ、次に初期値が計算されるという事です。
つまり、変数1、変数2...は未定義の値を保存する新しい記憶域にバインドされ、その環境で初期値が評価される。そして、その環境でボディが評価される。という事です。

環境という言葉を使わざるを得ませんでした。なんとなくわかるんですけど...ネ。

さて、letrecでは、各変数のバインディング(値はまだ計算されていません)がletrec本体(ボディ)からだけでなく、初期化部でも見えているわけです。
let*でも同じように他の変数が初期化部でも見えていますが、あくまで書かれた順に評価されていくわけなので、後に書かれている変数は見ることができません。

(let* (
(x y) ;<- y が定義されていないとエラーになってしまう。
(y 1)
)
(+ x y)
)

(letrec (
(x y)
(y 1)
)
(+ x y)
)
-> 2

とletrecではエラーになりません。要するに、こうであると再帰に利用できると。

さて、それでは、それぞれどういう場合に使うのかという事を考えて見ます。
まず、一番わかりやすいのはletrecです。再帰に使用する場合はこれしかありません。
つぎにlet*は、変数の初期化時に、ローカルの変数を使用したい時に使用します。
最後にletは、再帰も、ローカル変数の初期化にローカル変数も使用しない時に使用します。
letの外側の変数と、letで使用する変数が重複しても問題ないように、普段はlet*を使用するべきなんでしょうか。それならいっそのことletrecを使用したほうが??

何かいい例がないでしょうか???
posted by ほえ at 15:23| Comment(0) | TrackBack(0) | Scheme | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.seesaa.jp/tb/19400902
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。