SICP 読書ノート#28 - 3.2 評価の環境モデル (pp.138-147)
前回からずいぶん間が空いてしまった。
今回は「§3.2 評価の環境モデル」から。
初出じゃないけど用語がいろいろと出てくる。
- 環境(environments)
- フレーム(frames)
- 束縛(bindings)
- 大域(global)
- 外側の環境(enclosing environment)
- 変数の値(value of a variable)
- 未束縛(unbound)
- (束縛を)隠す(shadow)
何のことやらさっぱりという人は、 「§1.1 名前と環境」から 読み返すといいかもしれない。
評価の規則
すでに何度か出ている話題だけど、
(define (square x) (* x x)
は、
(define square (lambda (x) (* x x)))
のsyntax sugarである。
つまり、(define (square x) (* x x))
というのは、
(* x x)
手続きをsquareという変数に束縛しているにすぎない。
トップレベルで上記の式を評価すると、squareは大域環境に束縛されるので、 テキスト図3.2のような例になる。
単純な手続きの作用
(square 5)
という式が評価されると、x : 5
という束縛関係をもった環境が
生成されるが、これは大域環境ではなく手続きの実行時のみに生成される
一時的な環境である。テキスト図3.3のE1
がそれ。
また、これは``E1```の外部からは参照できないローカルな環境でもある。
逆に、E1
から大域環境を参照することは可能である。
グローバル→ローカルへは参照できないが、ローカル→グローバルへは参照できる。
よって、図3.3ではE1
から大域環境へと矢印が引いてある。
JavaScriptでのスコープチェーンと同じ概念だ(と思う)。
問題 3.9
(factorial 3)
の実行過程。(factorial 6)
を描くのはさすがに大変だったので...
局所変数の入れ物としてのフレーム
図3.3のE1
のxも局所変数だけれど、squareの実行時にしか現れないため
状態を保持する入れ物としては使えない。
しかし、以下のような手続きに対し、
(define (make-withdraw balance) (lambda (amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")))
その戻り値の手続きオブジェクトをある変数に束縛すると、 この手続きオブジェクトは外部の環境にあるbalanceを参照するため、 その結果、この手続きオブジェクトが解放されない限り、 balanceを含む環境も解放されないため、状態を保持する入れ物として使える。 まさにクロージャだ。
問題 3.10
(define W2 (make-withdraw 100))
まで評価が終わったタイミングでの実行結果。
環境構造としては initial-amount
の値がローカル環境に保持される点が、
テキストの前述の例とは異なる。
内部定義
さらに進んで手続きの中にローカルな手続きをもつ場合の例。 これまでの延長線で考えればよいので、特筆すべきことなし。
問題 3.11
(define acc (make-account 50))
評価時。
((acc 'deposit) 40)
評価時。
(define acc2 (make-account 100))
評価時。
次は「§3.3 可変データのモデル化」から。