##バグですね
##ケースの見落としでした。fixed
#;; env-lookup-int が異なる変数に同一のmacro(やsyntax?)を返すケースが出てきたため、free-identifier=? が #t になってしまいます
(let-syntax ((foo (syntax-rules ())))
(let-syntax ((bar foo))
(let-syntax ((f (er-macro-transformer
(^ (form rename id=?)
(id=? 'foo 'bar)))))
(f))))#;; あとinternal error出ました
(letrec-syntax ((foo (syntax-rules ()))
(bar foo))
42)
*** ERROR: [internal] cenv-lookup returned weird obj: (syntax-rules ())
While compiling: foo
While compiling: (letrec-syntax ((foo (syntax-rules ())) (bar foo)) 42)#SRFI-262のユーザ定義パターン構文を実装するのにSRFI-213 Identifier Propertyっぽいものが必要で、それは束縛に対応するオブジェクトが取れるとできそうなので、env-lookup-intが異なる束縛に異なるオブジェクトを返してくれるとできそうな気がしてるんですよね。
#ので (let-syntax ((bar foo)) ...) みたいなのはmacroをコピーしちゃうのがいいかなと思ってたんですが、begin や define みたいな特殊な特殊形式はコピーしてちゃんと動くのかなと書いてて思ったり。
#あれ、SRFI-147の第四の begin って定義グローバルに見えちゃっていいんですかね?
#gosh> (let-syntax ((dummy (begin
(define x 42)
(syntax-rules ()))))
#f)
#f
gosh> x
42#;; こんなのも
(define-syntax def
(syntax-rules ()
(_ (define foo 1))))
(let ()
(def)
(let-syntax ((dummy (begin
;; コメントを外すと動く
;; (define x #f)
(def)
(syntax-rules ()))))
42))
*** ERROR: syntax-error: the form can appear only in the toplevel: (#<identifier user#define.31a76c0> #<identifier user#foo.31a7680> 1)
While compiling: (begin (def) (syntax-rules ()))
While compiling: (let () (def) (let-syntax ((dummy (begin (def) (syntax-rules ())))) 42))#SRFI-147の begin のdefinitionってどう評価されてどう束縛を作るかってどこに書いてあるんでしょうか。
##あれ、renameされるから大丈夫と思ってたんだけどrenameされてないな
#srfi-147のその部分、私も不明確なんだけど、普通のクロージャみたいに環境を作ってもそれが作られるのがマクロ展開時で、通常のクロージャとフェーズが違うからうまくないんですよね。結局、beginを含むマクロ展開の度にグローバル環境に衝突しない名前を作ってくしかないなと思ったんだけど。
#マクロ展開の度じゃなくてマクロ定義の度、だな。
#実装を見た感じ、SRFI-147の begin のdefinitionはlet-syntaxの外側に展開されるみたいですね
#なのでこんな感じ'
#(let-syntax ((dummy (begin
(define x 42)
(syntax-rules ()))))
#f)
===
(let ()
(define x 42)
(let-syntax ((dummy (syntax-rules ())))
#f))###なるほどぅ。ふーむ、reference implementation動かしてみるか
#えぇ…let-syntax のbodyがスコープに入っちゃうんですね(キモくないか?)。(begin ...) がよそからrenameされてくるなら実際上は見えないから問題にならないとはいえ。確かにそこのtransformer specからしか見えないとは書いてない。
#あと、let-syntaxをletで囲っちゃうのはR6RSのlet-syntax splicingと互換性なさそうと思うんだけど。
#SRFI-147のreference implementationとしてはlet-syntaxはR7RSのsemanticsが念頭にあって、R6RSのsplicingなlet-syntax 等々は必要に応じてサポートしてねという感じっぽいですね
#"mutatis mutandis to all other natively provided binding facilities for keywords, e.g. let-syntax/splicing or define-syntax-parameter. " https://srfi.schemers.org/srfi-147/srfi-147.html #ところで、beginのdefinitionはlet-syntaxのbodyどころか他のclauseもスコープ入るように見えてそれでいいの感も
#;; こういう理解
(let-syntax ((x (begin
(define x1 42)
...
(syntax-rules ())))
(y (begin
(define y1 42)
...
(syntax-rules ()))))
#f)
===
(let ()
(begin
(define x1 42)
...
(begin
(define y1 42)
...
(let-syntax ((x (syntax-rules ()))
(y (syntax-rules ())))
#f))))#私もそういう理解です>他のclauseも入る
#ML読んでたら、この挙動の説明と共に
https://srfi-email.schemers.org/srfi-147/msg/4958409/
> The reasons for these rules are:
> 1) This SRFI should be implementable in R7RS-small.
> 2) The rules should be as intuitive as possible.
> 3) Sophisticated custom macro transformers (as the one in SRFI 148)
とあったので、とにかくR7RS-smallの範囲で実装できることを重視したかった(のとSRFI148で必要になるのかな?)と思いました。これが直感的とは到底思えませんが。
#それぞれのbeginがそれぞれのマクロ展開によって挿入されるなら衝突しないからヨシ!ってことなんだと想像します。