Let's start Scheme

2015-01-07

致命的目な勘違い

随分長いこと勘違いしていたのだが、以下のコードはエラーにならないといけない。
(import (rnrs))

(define-syntax aif
  (lambda (x)
    (syntax-case x ()
      ((_ test then)
       #'(aif test then #f))
      ((k test then else)
       (with-syntax ((it (datum->syntax #'k 'it)))
         #'(let ((it test))
             (if it then else)))))))

(aif (assq 'a '((a . 0))) it)
;; -> error
理由は、一つ目のパターンが展開された際に挿入されるaifは与えられた式のものではないためdatum->syntaxで生成される識別子が期待されるテンプレート識別子から生成されないため。_aifとして、置き換えの際に元の識別子が挿入されるようにすればOKになる。

何が問題かといえば、Sagittariusはこれをエラーにしない。さらにまずいことに僕自身がこの動作を期待してコードを書いている点である。datum->syntaxを多用した記憶はあまりないのだが、CLOS周りとかはかなり処理系の中身べったりで書いているので問題が起きる。また記憶が正しかったら(binary data)辺りもこれ系の動作を期待しているような気がする。

上記のような記憶にあって目に見えてる系のものならまだ救いがあるのだが(それでも影響範囲広いけど)、下記のような間接的に期待しているものがあると困る。
(define-syntax aif1
  (syntax-rules ()
    ((_ test then)
     (aif1 test then #f))
    ((_ test then else)
     (aif test then else))))

(aif1 (assq 'a '((a . 0))) it)
見た目的にはaif1aifの薄いラッパーで単に式をaifに移しているだけなのだが、これはR6RS的には動かない(はず)。が、Sagittariusでは動いてしまう。これ系のコードはdefine-methodで山ほど書いてる気がする。

ここらで一発マクロ周りの見直しをしないといけないな。この辺りを網羅したR6RS準拠なテストケースがほしいところである。PLTのやつはマクロ周りのテストが貧弱すぎて、全パスしてもスタート地点にすら立ってない感じががが・・・

No comments:

Post a Comment