SECDR-schemeをつくる の2 - EIODを読む

常識的なScheme処理系を実装するためには、expanderを実装しないといけない。いわゆるexplicit-renamingなexpanderの方がプロトタイピング等の面で都合が良いので、まずはexplicit-renamingに実装する。
minimumなexpanderの実装としては、例えばEIODが有る。EIODはSRFI-46なsyntax-rulesを実装している(また、SRFI-46のリファレンス実装としても提供されている)。

遊んでみる

一応R6RSに移植してみたので、単純にチェックアウトしてnmoshなりなんなりで使ってみることが出来る。
凄く遅いことに注意する。

oku@cage ~/repos/eiod-r6rs
$ nmosh eiod.scm
eiod> (define-syntax add-a (syntax-rules () ((_ rest ...) (list 'a 'rest ...))))
eiod> (add-a 1 2 3)
(a 1 2 3)
eiod> (add-a x y z)
(a x y z)
eiod>

先頭にシンボルaを付け加えるquote、add-aを定義してみた。正常に動作する。

EIODのcore scheme

EIODのcore言語は、

  • 構文
    • q - シンボルしか取らないQuote
    • def - シンプルなdefine(= (define (name arg0) ...) のようにして手続きを定義できない)
    • define-syntax
    • begin
    • syntax - qの拡張版。identifierも素通しする
    • get-env - (get-env) で、現在の環境を返す。
  • 手続き
    • delay*
    • if*
    • syntax-rules**
    • (その他バックエンドschemeの手続き)

ifやdelayが手続きとして提供されているのは地味に興味深い。EIODでは、内蔵のifやdelayをsyntax-rulesで提供し、core言語構文からifやdelayを省略している。

        (define-syntax if
          (syntax-rules () ((_ x y ...) (if* x (lambda () y) ...))))
        (define-syntax delay
          (syntax-rules () ((_ x) (delay* (lambda () x)))))))

syntax-rules**は、R6RS的な文脈で言うところのtransformerを生成するために使われる。syntax-rules**は3引数id?、new-id、デフォルトのellipsisのidentifierオブジェクトを取り、syntax-rules*を生成して返す。
syntax-rules*は、マクロ環境(マクロが定義された時点での環境)とsyntax-rulesのパラメタ(ellipsisとして使うシンボルとリテラル扱いされるシンボル)、syntax-rulesの変換ルールを取り、変換器(Transformer)を生成して返す。
変換器は2引数、変換対象のS式と変換時点での環境を取り、変換したS式を返す。