Let's start Scheme

2016-06-18

R7RSレコード

WG2の議論でレコードの健全性について出てる(c.f. record types)。個人的にレコードが暗黙的にアクセサを作るかどうかというのはとりあえずどうでもよくて(R6RSでは明示されなければ暗黙的に作るってなってるし)、健全性のテストコードが問題だった。

R7RS-smallのレコードは基本SRFI-9なのだが、SRFI-9ではコンストラクタタグとフィールドが同一の識別子でないとエラーとなっている。SagittariusのSRFI-9の実装はこの条件をbound-identifier=?でチェックしているので、テストコードもまぁ問題なく動くだろうなぁと思っていた。のだが、そうもいかなかった。

テストコードではtmpという識別子がコンストラクタタグとフィールドに並ぶ形になる。これらはfree-identifier=?を満たすが、bound-identifier=?は満たさない(識別子の挿入されるタイミングが違うため)。そのためSRFI-9の実装的には問題ない。何が問題か?R6RS版のdefine-record-typerecord-accessorの実装が問題だった。

R6RS版のdefine-record-typeは構文情報を引き剥がして下請けのレコード手続きに定義されたレコードの情報を渡すため、テストコードが生成するレコードが持つフィールド名は全てtmpになる(これはR6RS的には許容されている)。っで、record-accessorは与えられたレコードのk番目のフィールドの値を返す手続きを返すんだけど、このk番目にアクセスするためにスロット名でアクセスしていたのがまずかった。構文情報の引き剥がされてるので、単なるシンボルの比較になるんだけど、全部同じ名前なので常に最初にヒットしたスロットの値を返す。

どうしたか?普通にk番目でアクセスするように変更した。昔レコードをCLOSと統合した際に既にあった機能な気がしないでもないんだけど、なんでスロット名で引くようにしたんだろう?当時は気付いていなかったか、実はこの機能は後から外に出されたかのどっちかだろう。

一見するとマクロのバグのようで実は違ったという話。

No comments:

Post a Comment