MIT Schemeでdefine-macroする

yuniのレガシーなビルドシステムと決別する最後の壁になっていたMIT Schemeも、define-macro を手作りすることでサポートできた。というわけで、これで従来のビルドシステムから新しいビルドシステムに置き換えられる。。

新しいビルドシステムではLarceny、Vicare、picrin、 nmosh などいくつかの処理系のサポートを停止する。その代わりもっと別の処理系(主に非R6RS/R7RS処理系)をサポートする予定。nmoshを切るのは断腸の思いだけど、別の処理系をスクラッチで作る予定なのでそのための工数をどうしても空ける必要がある。

define-macro を逆sc-macroで定義する

... 今検索したらそのものズバリなStack overflowが有った。。

(define-syntax define-macro
  (syntax-rules ()
    ((define-macro (name . args) body ...)
     (define-syntax name
       (rsc-macro-transformer
         (let ((transformer (lambda args body ...)))
           (lambda (exp env)
              (apply transformer (cdr exp)))))))))

MIT Schemeにおける低レベルマクロは、chibi-schemeと同じく syntactic closure で、sc-macro-transformer は、

  • マクロが挿入したシンボル → マクロが定義された場所の意味で解釈される
  • make-syntactic-closure を通したシンボル → (一般に)マクロが使われた場所の意味で解釈される

という性質がある。ここで使用している rsc-macro-transformer で、マクロが挿入したシンボルはマクロが使われた場所の意味で解釈される。これは define-macro でやりたいことそのものと言える。

今回実装したものは、↑の実装に加えて、 define-syntax のための特別対応を入れている:

(define-syntax define-macro
  (syntax-rules (define-syntax)
    ((_ (define-syntax name synrule) body ...)
     ;; Skip syntax-rules
     (begin))
    ((_ (nam . args) body ...)
     (define-syntax nam
       (rsc-macro-transformer
         (let ((xformer (lambda args body ...)))
          (lambda (exp _)
            (apply xformer (cdr exp)))))))))

これは、yuniのランタイムが syntax-rules を備えないScheme処理系のために define-syntax をマクロで定義するコードを含んでいることによる。MIT SchemeはR5RS(R7RS)なので syntax-rules は当然持っており、yuniのコードにある (define-macro (define-syntax ...) ...) のコードは無視しなければならない。そうでないと define-macrodefine-syntax に展開され、無限再帰してしまう。。

MIT SchemeがR7RSでないところ

MIT Schemeは真の values を実装していない https://mjt.hatenadiary.com/entry/20170515/p1 以外に、yuniのテストケースで見つかったものとしては:

というのが有った。流石に values をエミュレートするのはパフォーマンスペナルティが大きすぎるけど、この辺はエミュレートした方が良いかもしれない。。

それ以前に、MIT SchemeのR7RSサポートは現状ライブラリパスを設定する方法が無く、yuniではR7RS処理系ではなく define-macro 処理系(yuniの用語でGeneric Scheme処理系)として扱っている。