マクロと internal define

Shiro さんから突っ込みが入った。いつもあんまり考えてないところを小突いてくれるので非常に嬉しい。ありがとうございます。で、マクロ…マクロは…綿菓子ぐらいうすらぼんやりとしか考えてませんでした…(顔
どういう問題が起きるかはわかったのだけれど、必ず正しく働くような対策を打てるほど抽象的に理解できた自信はありません。っていうかそもそもマクロ自体使ったことが無い ("Teach Yourself Scheme in Fixnum Days" 読みながらちょこっと打ってみたぐらい)

まずコードをコピー。

(define-macro (foo)
  '(begin (define x 1) (define y 2)))

(let () ;; (*1)
  (define z 3)
  (foo) ;; (*2)
  (list x y z)) => (1 2 3)

Shiro さんは、再帰的に eval を呼ぶ実装では (*2) の (foo) を展開して得られる begin が (*1) の let が作る frame にアクセスする手段が無いのではないか、ということを心配されているのではないかと思う。

これは問題ありません。

という論調に始まってぐだぐだ書いたけど、全部的外れなので、もっとよく考えてから改めて書きます。
(foo) に出くわしたときに、foo の body を評価したら (begin (define x 1) (define y 2)) というリストが返ってきますが、それをもう一度 (*foo の呼び出しが戻ってきてから*) 評価するので、展開で得られるリストは (*1) で作った frame で評価されます。

追記補足: SigScheme では関数呼び出しにおける tail expression を evaluator に返して evaluator が改めて評価するようにしていますが、この仕組みにマクロも便乗することを想定しています。

Scope についてもごちゃごちゃ考え込んだので反応が遅れましたが、こういうことでよろしかったでしょうか。

それと、マクロの実装方法について考えが進みました。ありがとうございます。

よろしくありませんね。理解できました。(*1) で作った frame に戻すタイミングが無い。

うーん、ちょっと汚いけど tail_flag (返ってきた値が tail expression であるかどうかを判定する参照渡しのフラグ) に放りこんでいる値で frame を戻すかどうか判定すれば切り分けれそうです。御指摘ありがとうございました。

あ、無理だ(度々すいませんが…)
再帰的に *eval を* 呼ぶんでは tail_flag なんか返せない。