評価の環境モデルでは, 手続きは常にコードと環境へのポインタである. 手続きは, lambda式を評価するという一つの方法でだけ作り出される. こうすると手続きが作れるが, そのコードはlambda式の本文から得られ, 環境は, 手続きを作るためにlambda式を評価した環境である. 例えば手続き定義
(define (square x) (* x x))を大域環境で評価することを考えよう. 手続き定義の構文は基盤の lambda式の構文シュガーである. それは
(define square (lambda (x) (* x x)))を使ったのと等価であり, (lambda (x) (* x x))を評価し, squareを結果の値に束縛する. すべては大域環境の中で行われる.
図3.2はこのdefine式の評価の結果を示す. 手続きオブジェクトは対であって, そのコードは手続きには仮パラメタは一つxがあり, 手続きの本体は(* x x)であることを規定している. 手続きの環境部分は, 手続きを作るためにlambda式を評価したのが大域環境なので, 大域環境へのポインタである. この手続きオブジェクトと, 記号squareを対応づける新しい束縛が大域フレームに追加される. 一般にdefineは, 束縛をフレームに追加することで, 定義を作り出す.
図3.2 大域環境で(define (square x) (* x x))を評価して生じた環境構造
手続きが作り出されるところを見たので, 手続きをどう作用させるか説明出来る. 環境モデルはこう規定する: 手続きを引数に作用させるには, パラメタを引数の値に束縛するフレームを含む新しい環境を作り出す. このフレームの外部の環境は, 手続きが規定する環境である. そしてこの新しい環境の中で手続き本体を評価する.
この規則の実行の仕方を見るため, 図3.3に大域環境で式(square 5)を評価する時に作り出された環境構造を示す. squareは図3.2で生成した手続きである. 手続きを作用させると, 図でE1とラベルのついた新しい環境が出来る. 最初のフレームで, 手続きの仮パラメタxが引数5に束縛される.
このフレームから上に伸びるポインタは, フレームの外側の環境が大域環境であることを示している. 大域環境が選ばれたのは, これがsquareオブジェクトの一部が表示している環境だからである. E1の環境の中で手続きの本体(* x x)を評価する. E1でxの値は5だから, 結果は(* 5 5)つまり25である.
図3.3 大域環境で(square 5)を評価する時作り出された環境
手続き作用の環境モデルは, 二つの規則に要約出来る:
• 手続きオブジェクトを一組の引数に作用させるには, フレームを構成し, 手続きの仮パラメタを, その呼出しの引数に束縛し, それから今構成した新しい環境の文脈で, 手続きの本体を評価する. 新しいフレームは外側の環境として, 作用させている手続きの環境部分を持つ.
• 手続きを, 与えられた環境に関してlambda式を評価して作り出す. 結果の手続きオブジェクトはlambda式の本文と手続きが作り出された時の環境へのポインタである.
またdefineを使った記号の定義は, 現在の環境フレームで束縛を作り出し, 表示された値をその記号に割り当てる.13 最後に, そもそも環境モデルを取り入れさせた演算のset!の振舞いを規定する. ある環境で, 式(set! 〈name〉 〈value〉) を評価すると, その環境でその変数の束縛を探し, 束縛を変えて新しい値を表示するようにする. つまり環境でその変数の束縛を含む最初のフレームを見つけ, そのフレームを修正する. 変数が環境で未束縛なら, set!はエラーとなる.
これらの評価規則は置換えモデルよりかなり複雑であるが, まだそれなりに直截だ. その上この評価モデルは, 抽象的ではあるが, 解釈系が式を評価する方法の正しい記述を提供する. 4章で, このモデルが実用の解釈系を実装する青写真として役立つことが分る. この後の節では典型的プログラムを解析し, モデルの細部を解説する.
12
代入は評価規則の第一段に, 不安要素を持ち込む. 問題3.8に示したように, 代入があると, 組合せの部分式を
評価する順によって異る値を生じる式が書ける. だから正確には第一段の評価の順を(例えば左から右とか右から左と)規定すべきである. しかし, この順はいつも実装の細部と考えられていて, 特定の順に依存するプログラムを書くべきではない. 例えば巧妙な翻訳系は, 部分式を評価する順を変えて最適化を図るかも知れない.
13
現在のフレームに変数に対する束縛が既にあれば, 束縛が変更になる. これは記号の再定義が出来るので,
便利である. しかしdefineは値を変えるのにも使えるということで
set!を明示的に使わなくても代入が出来るという議論が出てくる. このため人によっては, 既存の記号の再定義には, エラーか警告をだすべきだという.