Scheme で一意なオブジェクトを生成する方法に苦心している事例を見ていて、処理系の挙動に頼らない R6RS の範囲内で何かもっと簡単な方法がないかということを考えていた。
まず問題を整理してみよう。 実行時に確実に区別可能なオブジェクトを生成するのは難しいことではなくたとえば (list 'foo) とでもすれば別の呼び出しでの (list 'foo) とは同一ではないことが保証される。 つまり (eq? (list 'foo) (list 'foo)) は必ず偽となる。 しかしここでは同じ場所では同じオブジェクトに評価されて違う場所では違うオブジェクトに評価される必要があり、マクロの使用場所を区別できることが必要なのだ。 呼び出す度に異なっていては目的が達成できず、使われる場所が同じなら同じでなければならないことを要件とすることが厄介である。
具体例で言えば
#!r6rs
(import (rnrs)
(only (unique) unique unique=?))
(define (foo)(unique))
(define (bar)(unique))
(assert (unique=? (foo) (foo)))
(assert (unique=? (bar) (bar)))
(assert (not (unique=? (foo) (bar))))
が成立するようなライブラリ unique を定義可能かということになる。
私なりに考えて構文オブジェクトを利用する方法を思いついて以下のようなものが出来た。 通常は構文オブジェクトはマクロ展開フェイズで扱うものだが実行フェイズで使うことが出来ないわけではない。
#!r6rs
(library (unique)
(export unique unique=?)
(import (rnrs))
(define-syntax unique
(syntax-rules ()
((_)
(let-syntax ((foo (syntax-rules ()))) #'foo))))
(define unique=? free-identifier=?))
いくつかの処理系で試してみて期待通り動作しなかったものもある。
まず期待通り動作したのは
である。
駄目だったのは
- Ypsilon 0.9.6 (Windows で使っている都合からバージョンが古い)
- Sagittarius 0.9.14
だった。
私の認識している R6RS の解釈に誤りがあるだろうか? 処理系のバグだろうか?