Schemeをつくろう(8) 環境について。
さて、環境について考えてみます。ここら辺はSICPに書いてあるハズなんですが、まだ「全く読んでいない」ので「僕の想像」で作ってみることにします。
復習
まず、環境をリストで作りました。
((cons . function:0x8049307[2]) (cdr . function:0x8049360[1]) (car . function:0x8049335[1]) (+ . function:0x804875d[99]))
リストの先頭から見て、シンボルと一致したら、値を返す。という非常にシンプルな作りになってます。
新たな環境を作るには、リストの先頭に環境を加えればいいだけです。同じ値があったら上書きされたように見えます。
ここに新たな環境を加えたいんです!!
スコープについて
今までの僕のスコープのイメージはこんなんでした。
+-main------+ |x : 1 | |y : 2 | | +-func-+ | | | x : 3| | | +------+ | +-----------+
funcにいるとき、yが欲しいとすると、
「funcの中に、yが無いので、mainに取りにいく」
もし無かったら、上に見に行って、また無かったら、上に見に行って・・・。
こんな複雑な事をしてると思ってました。
でも、違うかもしれないという事に気付いた。
環境のコピーを渡せ
どういうこと?
mainの環境があります。
+-main------+ |x : 1 | |y : 2 | +-----------+
funcに、環境のコピーを渡します。
+-func------+ |x : 1 | |y : 2 | +-----------+
xは3なので、funcのなかで環境を上書きします。
+-func------+ |x : 3 | |x : 1 | |y : 2 | +-----------+
上書きされた部分を除くと、
+-func------+ |x : 3 | |y : 2 | +-----------+
スコープが出来ました。親を見る必要はありません。
環境のコピーといっても、リストの先頭アドレスを渡すだけです。
あくまで「僕の想像」です。僕はSchemeレベル3です。
define(変数)の実装
ポイントは、
- defineは環境を返す。
- evalは環境と値(オブジェクト)を返す。
- 通常の関数は環境は返さない。値(オブジェクト)だけ。
- 引数を作用させるとき(僕の実装ではeval_map)は環境を返さない。
- applyというのかも知れないけど、僕がまだそこまで達してないので。
defineは環境を返す特別な関数という定義にしました。
defineは特別な関数
実装中にdefineが特別な関数であることを知りました。
僕の失敗
> (define hoge 1) ERROR : eval : undefind value
変数を定義しようと思ってるのに、変数が先に作用してしまいました。
hogeは作用させずにシンボルとして、defineに渡さなければなりません。
defineは普通の関数とはちょっと違う特別な関数である事を知りました。
で、こんな感じになりました
ソースは自身が無いので略(笑
input> (define abc (+ 1 2 3)) 6 input> abc 6 input> (cons (define a 1) (define b 2)) (1 . 2) input> a ERROR : eval : undefind value
スコープ完成!?
defineが環境以外に値を返すかどうか。という所で迷ったのですが、評価後の値を返す事にしました。
- Gaucheの場合、(cons (define a 1) (define b 2))は、(a . b)となります。シンボルを返すようです。
gosh> (symbol? (define a 1)) #t
- MzSchemeの場合、エラーです。defineは何も返さない。
ここら辺は「僕の想像」なので、Schemeの定義とは違うかもしれません。
大きな勘違いがありそうな予感。