レコード型を定義する


Tags: R6RS, レコード

レコード型を定義するには define-record-type 構文を使う。 define-record-type の構文はおよそ次の通りである。

 (define-record-type <name-spec>
   (fields
    <field-spec>
    ...))

<name-spec>

 <record-name>

 (<record-name> <constructor-name> <predicate-name>)

のいずれかの形式を取り、

 <record-name>
    ≡ (<record-name> make-<record-name> <record-name>?)

である。 <record-name> は定義されるレコード型の名前であり、 <constructor-name> はレコード型のインスタンスの構築子の名前、 <predicate-name> はオブジェクトがそのレコード型のインスタンスかどうか調べる述語の名前になる。 <field-spec> はそのレコード型の持つフィールドの特性について宣言し、

 (mutable <field-name> <accessor-name> <mutator-name>)
 (immutable <field-name> <accessor-name>)
 (mutable <field-name>)
    ≡ (mutable <field-name> <record-name>-<field-name> <record-name>-<field-name>-set!)
 <field-name>
    ≡ (immutable <field-name>)
    ≡ (immutable <field-name> <record-name>-<field-name>)

のいずれかの形式を取る。 mutable と宣言されたフィールドはインスタンス化後も変更可能であり、 immutable と宣言されたフィールドは変更が不可能である。 <accessor-name> はフィールドの値を取り出す手続きの名前になり、 <mutator-name> はフィールドの値を変更する手続きの名前になる。フィールドの並び順には意味があり、レコード型構築子は引数に取ったオブジェクトをその順番で各フィールドに設定してゆく。

fields 節以外の節については別頁で説明する。

例えば、変更不可能な name フィールドと変更の可能な age フィールドを持つ person レコード型は次のように定義できる。

(import (rnrs))

(define-record-type person
  (fields
   (immutable name)
   (mutable age)))

(define bob (make-person 'bob 32))

(person-name bob) ; => bob
(person-age bob) ; => 32

(person-age-set! bob 33)
(person-age bob) ; => 33

必要に応じて述語やアクセサの名前を明示して指定することもできる。例えば複素数を表すレコード型を作るとすると次のように書ける。

(import (except (rnrs)
                make-rectangular
                complex?
                real-part
                imag-part))

(define-record-type (complex make-rectangular complex?)
  (fields
   (immutable re real-part)
   (immutable im imag-part)))

(define x (make-rectangular 1 2)) ; 1+2i

(real-part x) ; => 1
(imag-part x) ; => 2