yhara.jp

Recent Posts

er-macro-transformerのrenameは衝突を回避するだけじゃない

2023-11-08
Tech

Schemeの話。

Gaucheでsyntax-rulesとer-macro-transformerを試してたんだけど、少し挙動が違う点に気づいた。(Gaucheを使ったのは、単に両方を実装している処理系として最初に思いついたため)

まず、以下のように定数thePiを提供するpi.scmがあるとする。

(define-module pi
  (export thePi)
  (begin
    (define thePi 3.14)))

それを使うutils.scmがあるとする。 utilsは、マクロloggを提供する。そのマクロの実装に先程のthePiを使うとどうなるか?

(define-module utils
  (use pi)
  (export logg)
  (begin
    (define-syntax logg
      (syntax-rules ()
        ((_ str) (display thePi))))

結果だが、以下のようにthePiの値が表示された。main.scmではモジュールpiをuseしていないわけだが、これが許される方が、マクロの利用者としてはこのほうが使い勝手がよいといえる。だって「マクロを使うときにはその実装に使われたすべてのモジュールを再度useしなければならない」だと面倒でしょ。

> gosh -I. main.scm
3.14

一方で、er-macro-transformerの場合

utils.scmを以下のように書き換えてみる。

(define-module utils
  (use pi)
  (export logg)
  (begin
    (define-syntax logg
      (er-macro-transformer
        (lambda (form rename compare)
          `(display thePi))))))

今度は、main.scmでthePiという変数が見つからないというエラーになった。

>gosh -I. main.scm
*** ERROR: unbound variable: thePi
    While loading "./main.scm" at line 8
Stack Trace:
_______________________________________
  0  thePi
        [unknown location]

これは、展開結果の(display thePi)がmain.scm側で評価されるから。このエラーをなおすには、以下のようにrenameを使ってやる。

      (er-macro-transformer
        (lambda (form rename compare)
          `(display ,(rename thePi)))))

ER macroのrenameは「呼び出し側の名前との衝突を避ける」という文脈で説明されることが多いが(Gaucheでの説明)もそうなっている)、呼び出し側でimportされていない名前を使いたい場合にもrenameが必要、という話でした。

(追記:syntax-rulesの場合、展開結果が自動的にrenameされる、といえる。)

More posts

Posts

(more...)

Articles

(more...)

Category

Ads

About

About the author