Artifact Content
Not logged in

Artifact 10868a3c96e6a326093906531246cff02125c9e5


@macro レイヤをどう実装するべきか

- 「マクロレイヤは実行時レイヤの先に実行される」が
- 「マクロ定義内で実行時関数を(構文木の操作のためなどに)使えると便利である」
- 「といって、特に関数内マクロなどについて、実行時のスコープが定まるのを待ってから
    毎回関数実行のたびにマクロ展開していると遅い」

ざっと調べた結果。
普段スコープ内マクロとか全く使わないので間違ってる恐れが多々あるので注意。

Common Lisp
  http://www.lispworks.com/documentation/HyperSpec/Body/m_defmac.htm
  http://www.lispworks.com/documentation/HyperSpec/Body/03_abaa.htm

  - トップレベルの defmacro の body は compile 時に実行できなくてはいけない
  - トップレベル defmacro の出現以降の式は全て一度に compile 時展開される (must?)
  - (eval-when (:compile) (require ...)) 的なかんじの指定をすることで
    コンパイル時にライブラリ関数をimport等はできるので、それでまあ実行時間数もわりと
    コンパイル時にも使える

  - lexical scope 内での defmacro は環境も普通にキャプチャできるし普通に"実行時"に展開される。
    すなわち関数本体の実行は、というか書く式 "form" の、eval はまず macro なら展開してから
   eval、というステップを踏む

  たいていの「コンパイルできる」普通のマクロは速く処理できて、
 実行時環境キャプチャするようなこともしたければ自由に出来るけど遅くていいやという感じか。


R6RS
  http://practical-scheme.net/wiliki/wiliki.cgi?R6RS%3a%E7%BF%BB%E8%A8%B3%3aR6RS%3a10%20Expansion%20process

 全部コンパイル時にやる。
 実行時束縛 (define や (let や (lambda は、hygenic 性のために変数束縛であることは記録されるし、
 あと微妙にマクロ展開の評価順序も変えるけど、基本的にはマクロ展開器はこの辺の special form を素通りして
 いきなりコンパイル時に中まで展開をかける。以降、実行時はまったく展開は起きない。

 - lexical scope のキャプチャは?
   spec ではどういう扱いなのかいまいちよくわからない。
  - Gauche はコンパイル時に解決されるものだけは解決してくれた。
    (lambda (x)
            ... (let-syntax ... x ...) ...
      この x は stray local variable エラーになるけど
    (let ((x 1))
            ... (let-syntax ... x ...) ...
      は行ける

 現実的で妥当だと思うけどスコープの概念が錯綜している感が初見ではして
 (といっても深く考えるとそうでもないように思えてくるけど)すこし慣れにくいかも