Gauche:evalと環境
R5RSのevalは、第二引数に「環境指定子(environment specifier)」を 取ると定義されている。
(eval form environment-specifier)
しかし、環境指定子の具体的な実装は処理系に任されている。
処理系によっては、レキシカルスコープを含めた環境を ファーストクラスオブジェクトとして取り出せるものがあるから、 そういう処理系独自の拡張を念頭に置いた仕様だろう。
Gaucheでも将来はそういう拡張をするかもしれないが、 現在のところは、単なるモジュールを環境指定子として使っている。 モジュールはトップレベルの名前空間を規定するものだ。 evalは、form内の自由変数を、第二引数に渡されたモジュール内で 解決する。
;; デフォルトではプログラムはuserモジュールで実行される。
;; R5RSのinteraction-environmentは単にuserモジュールを返す。
gosh> (interaction-environment)
#<module user>
;; userモジュール中で変数xを定義
gosh> (define x "I'm in the user module")
x
;; userモジュール中でevalしてみる
gosh> (eval 'x (interaction-environment))
"I'm in the user module"
;; evalはレキシカルな環境の影響を受けない。
gosh> (let ((x "local"))
(eval 'x (interaction-environment)))
"I'm in the user module"
;; 新たなモジュールを作る。
gosh> (define-module my-module)
#<module my-module>
;; 新たなモジュール内で変数xを定義
gosh> (with-module my-module
(define x "Hey, I'm in my-module."))
x
;; userモジュールのxには影響無し
gosh> x
"I'm in the user module"
;; my-module中でevalしてみる
gosh> (eval 'x (find-module 'my-module))
"Hey, I'm in my-module."
;; evalを使ってmy-moduleに定義を追加
gosh> (eval '(define y "YYyyyy") (find-module 'my-module))
y
;; userモジュールからは見えない。
gosh> y
*** ERROR: unbound variable: y
Stack Trace:
_______________________________________
;; my-moduleからは見える
gosh> (eval 'y (find-module 'my-module))
"YYyyyy"
define-moduleはモジュールに名前を付けるが、 Gaucheでは無名のモジュールを作ることもできる。
gosh> (define anon-module (make-module #f)) anon-module gosh> anon-module #<module #> gosh> (eval '(define x "I'm in anonymouns module.") anon-module) x gosh> (eval 'x anon-module) "I'm in anonymouns module."
無名のモジュールへの参照が無くなりガベージコレクトされると、 そのモジュール内の束縛も全てガベージコレクトされる。 一時的な評価環境を作るのに便利。