明示的に書いてある点
ライブラリAは複数のプログラム、ライブラリから読み込まれた際には読み込みが複数回に渡ることがある。これは非常に簡単で、以下のようなものになる。
(define-library (A) (export inc!) (import (scheme base) (scheme write)) (begin (define inc! (let ((count 0)) (lambda () (set! count (+ count 1)) count))) ) ) (define-library (B) (export count-B) (import (scheme base) (A)) (begin (define count-B (inc!))) ) (define-library (C) (export count-C) (import (scheme base) (A)) (begin (define count-C (inc!))) ) (import (B) (C)) count-B ;; -> 1 count-C ;; -> 1 or 2ライブラリBがインポートされるのが先と仮定すると、
count-C
の値は未定義である。これはライブラリAが複数回評価される可能性があるからであり、これは明示的に書いてある。書いてない点
いっぱいあるんだけど、とりあえず以下。
(import (scheme eval)) ;; library (A) is the same as above (eval '(inc!) (environment '(A))) ;; -> 1 (eval '(inc!) (environment '(A))) ;; -> ???これ微妙に書いてない気がする。これは多分、2を返すのが正しい(はず)。根拠としては§5.6.1の最後にあるこれ:
Regardless of the number of times that a library is loaded, each program or library that imports bindings from a library must do so from a single loading of that library, regardless of the number of import declarations in which it appears. That is,(import (only (foo) a))
followed by(import (only (foo) b))
has the same effect as(import (only (foo) a b))
.
environment
の引数はimport specである必要があるので、無理やり読めば上記に該当するような気がする。ついでに、プログラムの定義が一つ以上のimport
句と式と定義されてる、かつライブラリが複数回読まれる可能性は、読み込みが複数のプログラムもしくはライブラリからなので。気にしてるのはこれ
(import (scheme base) (prefix (scheme base) scheme:))一つのプログラム内だから一回のみかなぁとは思うんだけど、微妙に読み取り辛い気がする。
これはどうなるんだろう?
;; a.scm (import (A)) (inc!) ;; other file (import (scheme load)) (load "a.scm") (load "a.scm")
load
は同一の環境で評価するけど、二つのプログラムになるから、両方とも1を返してもいいのかな?それとも、load
で読み込まれたファイルは呼び出し元と同じプログラムということになるのだろうか?まぁ、こんなことを考えているんだけど、実際の処理系で複数回ライブラリを評価するのは見たことがないので「完全処理系依存フリー」とかいうことをしなければ気にすることはないのではあるが。
2 comments:
ライブラリが状態を持ったらポータブルではない、とだけ解釈するしかないと思います。実用上は状態を持たせることが便利であるケースは多いのですが。
似たような落とし穴はプログラムを分割開発する場合にどうしても出てくることで、例えば http://blog.practical-scheme.net/shiro/20100803-static-member-in-header なんかも本質的には同じ問題だと思います。
(プログラムのモジュール分割とモジュールが状態を持つことについては70年代だか80年代くらいに色々考察されていたような気がするんですが手元にポインタがありません。)
ライブラリインスタンスは必ずひとつ、ということを強制しようとすると、コンパイルやリンクを含むツールチェインに渡って考えなければならず、RnRSでは手に余るということでしょう。実用指向なら何らかの規定が欲しいところではありますが、それをRnRSでやるべきか、別の規格でやるべきかは議論のあるところだと思います。
なるほど、確かにそう解釈するのが一番っぽいですね > ライブラリが状態を持ったらポータブルではない
気になるのは状態を持たなくてもポータブルじゃない場合がある点ですね。例えばSRFI-1のfirstをリネームエクスポートしてプログラムAで(scheme base)のcarと比較した場合に同一の束縛であることが保証されないとか。これも、ライブラリ跨いだら束縛が同一であることは保証されないと考えるしかなさそうですけど。
ツールチェインのところまでは考えが及びませんでした。確かにRnRSで規定するには荷が重いかなぁと思いますね。別の規格でしてしまうと、それが例えSRFIであっても、追従するかしないかは処理系任せになってしまうので、難しそうな問題です。(R6RSでは規定してた気がしたのですが、読み返してみると何処にも(少なくとも明示的に)書いてないような気がするので気の所為だったのかなぁ?)
Post a Comment