R7RS-smallのレコードは基本SRFI-9なのだが、SRFI-9ではコンストラクタタグとフィールドが同一の識別子でないとエラーとなっている。SagittariusのSRFI-9の実装はこの条件を
bound-identifier=?
でチェックしているので、テストコードもまぁ問題なく動くだろうなぁと思っていた。のだが、そうもいかなかった。テストコードではtmpという識別子がコンストラクタタグとフィールドに並ぶ形になる。これらは
free-identifier=?
を満たすが、bound-identifier=?
は満たさない(識別子の挿入されるタイミングが違うため)。そのためSRFI-9の実装的には問題ない。何が問題か?R6RS版のdefine-record-type
とrecord-accessor
の実装が問題だった。R6RS版の
define-record-type
は構文情報を引き剥がして下請けのレコード手続きに定義されたレコードの情報を渡すため、テストコードが生成するレコードが持つフィールド名は全てtmp
になる(これはR6RS的には許容されている)。っで、record-accessor
は与えられたレコードのk番目のフィールドの値を返す手続きを返すんだけど、このk番目にアクセスするためにスロット名でアクセスしていたのがまずかった。構文情報の引き剥がされてるので、単なるシンボルの比較になるんだけど、全部同じ名前なので常に最初にヒットしたスロットの値を返す。どうしたか?普通にk番目でアクセスするように変更した。昔レコードをCLOSと統合した際に既にあった機能な気がしないでもないんだけど、なんでスロット名で引くようにしたんだろう?当時は気付いていなかったか、実はこの機能は後から外に出されたかのどっちかだろう。
一見するとマクロのバグのようで実は違ったという話。
No comments:
Post a Comment