展開のフェーズの話。(というよりは依存関係か)
たとえばこのコード
(library (my-lib)
(export sub)
(import (rnrs))
(define (bigger? x)
(or (> x test)))
(define-syntax sub
(lambda (x)
(syntax-case x ()
((_ a b)
(or (bigger? (syntax->datum #'a))
(syntax (let ((x b))
(- x 10))))))))
(let ()
(sub 10 x)))
このコード、一見何もないように見えるけど、走らせると死ぬ。一見何もないように見えるという段階でR6RSのライブラリについて理解してないのだが・・・orz
問題は、subの中で使われているbigger?がフェーズ0でしか参照されないこと。
subが展開されるのはひとつ前のフェーズ1なので、単純にunbound variableな例外を投げてくる。
これを解決するには、bigger?を別ライブラリにして、expandで読み込む必要がある。
まさにこれにはまっていて、
自前実装のコンパイラにライブラリを実装して、R6RSのライブラリにコンバートしてコンパイルなんてことをやっているのだが、
依存関係の解決が面倒くさすぎる。
たとえば、こんなコード
(define something 10) (define-macro (generate) `(make-vector ,(- something 5))) (define generated (generate))こんな感じのをライブラリにするとなると、somethingは外出しにしないと上記の理由で死ぬ。
というか、すでに死んでいる・・・
(逆に考えれば、意外と適当に実装したのに、その辺もうまいこと動いているということだが・・・)
これはライブラリの仕組みが悪いのか、Schemeにマクロがあるのが悪いのか(そもそも良い悪いの問題ではないと思うが)
わからないけど、あまり相性が良くない気がする。
プログラマがいろいろなことを気をつければいいのだけど、R5RSで書いてて、R6RSにコンバートするって時に(まさに今)非常に不便・・・