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の定義とは違うかもしれません。


大きな勘違いがありそうな予感。