ささだ

先生! 初心者ですわかりません教えてください。

マクロ

Lisp はこれがあるから辞められない、と聞くんですが、使ったことがないのですよ。

R5RS しか知らないんですが、 define-macro ってなんですか?

t-y-scheme には解説がありましたが・・・。

マクロ展開のタイミングは何時?

Scheme:マクロの効用 では、

但し、処理系によって最適化の方策は異なるので、なんでもかんでもマクロにすれば速くなるとは限らない。ナイーブなインタプリタ(ほとんど無いと思うけど)では評価の度にマクロが展開されるかもしれない。モジュールを解釈するコンパイラなら、逆にモジュール内ローカルの関数定義は勝手にインライン展開してくれるかもしれない。

とかかれているんですが、次のような例ではどうしましょう。

(define cont #f)
(define-syntax test
   (syntax-rules ()
     ((test expr) (begin (display "=") (display expr) (newline)))))

(test 1)
(begin (call/cc (lambda (c) (set! cont c)))
       (test 100))


(define-syntax test
   (syntax-rules ()
     ((test expr) (begin (display "*") (display expr) (newline)))))

(test 1)
(cont 10)

;; DrScheme
=1
=100
*1
*100   ;; ==> ここが =100 か *100 か

こんなの無視?(Gauche ではそうなってるようですね)

ちょっと実装について思いを馳せてみると、define-syntax で再定義するときに既に展開したマクロをキャンセルするような何かを作ってみたり。うーむ。それか、そのマクロで既に展開されているかをチェック、つまり変換結果をキャッシュしておいて、それがヒットするならばそれを使う、というような手法なのかなぁ。ああ、いいな、これ。これで行こうかな。(自己完結かよ)

誰もマクロ再定義(とか、組込み関数再定義とか)なんてしねーよ、だからこんなの無視して問題ない、っていう論旨なら、それはそれで納得します。

組み込み関数での同様の問題は

(begin
  (display (+ 1 2))
  (set! + -)
  (display (+ 1 2)))

です。

Rucheme では、こういうのどうすればいいのかわかんなかったので、「ナイーブな」実装になってます。


(begin
  (define + -)
  (+ 1 2))    ;;=> Gauche: 3

あれ、でもこれは -1 なんだな。

(let ((+ -))
  (+ 1 2))     ;;=> Gauche: -1

あ、begin での定義はトップレベルでの定義と同じなのか。失礼しました。

More ...