Scheme修行 第20章 店には何がある?
再びここでschemeインタープリタを作成します。サポートするSchemeの仕様はこの本に出て来る仕様そのもので、例えばcall-with-current-continuationはletccとして定義されているし、atom?は組み込みとして定義されます。
ノート:
(car (quote ())はエラーとなる。空リストはconsセルが存在していない。
関数lookupは引数のtableを関数としてnameに適用してその値を得る。
関数extend
- extendは新しい名前name1とその値valueとtableを引数に適用する関数
- テーブルとしての関数(クロージャ)を値とする
- その関数(クロージャ)は名前name2に適用し…
- name2がname1と同じ場合はvalueを値とする
- そうでない場合はname2にtableを適用してその値とする
このtableは第10章の時の様なリストではなく一連のクロージャ。関数extendがどんどんクロージャを増やして行く。
eは(define × 3)です。
の×に見える部分は恐らくシンボルとしてのx(エックス)。つまりこの部分はこのインタープリタに解釈させるプログラムに相当する。
第10章のschemeインタープリタにdefineやletccを付け加えるつもりらしい。
関数valueで
- …
- 式eが"define"で始まるリストの場合、関数*defineで処理をする
- そうでなければ、関数meaningで処理をする
global-tableはextendが作った一連のクロージャを参照している。
box
boxはクロージャの形態を取るある種のオブジェクトを返す関数。
返されたクロージャを関数として適用されると、引数として渡されたセレクタを適用し返す。
セレクタには引数があり、各引数はオブジェクトが提供している全てのメソッドに相当する。
ゲッターメソッドに相当するのはアトリビュートの値。セレクタがその値をそのままセレクタの値とすれば、それが関数として適用したboxの値として利用者側に返る。
セレクタに引数として渡されるメソッドを適用するクロージャを渡せば、メソッド呼び出しとして利用出来る。
boxの場合は第1引数としてboxに結び付いている変数itの値、第2引数としてitの値を変更するメソッドをセレクタに渡している。
関数setbox
セレクタとして第2引数のsetメソッドを適用するクロージャを使う。boxに結び付いている変数itの値をnewに変更する。
定義内で適用しているboxは引数として渡されたクロージャであり、そのクロージャを返す関数boxとは別物。
関数unbox
セレクタとして第1引数のitの値をそのまま返すクロージャを使う。itの値が得られる。
ここでも、定義内で適用しているboxは引数として渡されたクロージャであり、そのクロージャを返す関数boxとは別物。
関数the-meaning
第10章では関数valueの定義で(meaning e (quote ()))と空っぽのテーブルを出発点にプログラムeを評価していた。ここでは事前に名前と値が登録されている(かも知れない)global-tableから値を引っ張る関数lookup-in-global-tableを引数にmeaningを呼び出している。
常に最新のglobal-tableと同じようなものですが、現在のglobal-tableと同じようなものではありません。
はlookup-in-global-tableはプログラムを解釈して行く段階でその中身が変化する可能性があり、名前を引く段階で最新のglobal-tableを参照するので、それは現時点での(the-meaning呼び出し時点での)global-tableと同じとは限らない、と解釈。
次の値は何ですか。(set! x 5)
答えはありません。
set!の関数値はSchemeの仕様として未定義。
その後の『(value e)は何ですか。』は(value e)の値を尋ねているものと解釈。
*lambda
*lambdaは第10章とは異なる定義。第10章では定義をそのままtableに追加して、参照される時に評価していた。
ここでは式eとその時点でのテーブルtableを取り込んだクロージャを返している。
そのクロージャはlambdaの関数定義部分を解釈するbeglisを適用する。
関数box-all
argsとして渡された変数のbox(クロージャ)をリストに纏める。
ここで作成した一連の関数が、必要なすべての定義について動作するようにするためです。
言葉の意味としては理解出来ないが、
>>(let …)の形をした式は、それなしで済ませる方法を知っているので、扱えなくても差し支えありません。