Let's start Scheme

2015-03-18

R6RS非準拠部分

Vicareの作者のブログを眺めていたらSagittariusでは(最初のリリースから)放置していた非互換を指摘されていた。こんなの。
;; from: http://marcomaggi.github.io/weblog/2015-February-16.html#fn-2
#!r6rs
(import (rnrs))

(define (fun)
  (mac))
(fun)
(define-syntax mac
  (syntax-rules ()
    ((_)
     (begin
       (display 123)
       (newline)
       (flush-output-port (current-output-port))))))
原因は分かっている。Sagittariusではスクリプトとして読まれたファイルは全て読まれた順に評価されるが、R6RSは「全て読み込んでマクロを展開してから実行しろ」という風に定めている。ちなみに0.6.2(か0.6.1からだっか)からはbeginで囲むと動く。ついでに、libraryフォームの中でも動く。このケースであればオプションを追加してそのオプションが指定された場合は一度ファイルを全部読み取って何かしらで包んでやればよいということになる。beginではまずいのでそれように何か足してやる必要はある。考えているのはAndre van Tonderの展開器で使われているprogramとか。

じゃあ、それを入れればいいじゃん?という話になるのだが、話はそんなに簡単でもない。現状ではトップレベルで定義されたdefine-syntaxのコンパイル及びトップレベルのマクロの展開しかしない。つまり、let(rec)-syntaxを用いてトップレベルに定義されるマクロは展開されないのである。つまり、これはbeginで包んでやっても動かない。
#!r6rs
(import (rnrs))
(define (fun)
  (mac))
(fun)
(let-syntax ()
  (define-syntax mac
    (syntax-rules ()
      ((_)
       (begin
         (display 123)
         (newline)
         (flush-output-port (current-output-port)))))))
これもlet(rec)-syntaxで定義されているマクロを評価してやればいいじゃん?と思うかもしれないが、話はそんなに簡単でもない。この例であれば動くのだが、例えば内側にdefineがあって、その中で局所マクロが使われていた場合に困る。

と、ここまで書いて案が浮かんできた。問題になるのは、局所マクロの評価をした後にdefineがコンパイルされない(すると問題になる)という部分だったのだが、ライブラリ及びトップレベルのbegin展開時に対応するコンパイル時環境を式に保持させればちょっとした手間でいけるような気がしてきた(現状よりさらにメモリを喰うようになるのが気になるが・・・)。ちょっと頑張ってみようかな。

No comments:

Post a Comment