The ‘define-record-type’ syntax described in SRFI 9 is a slight simplification of one written for Scheme 48 by Jonathan Rees. Unlike many record-defining special forms, it does not create any new identifiers. Instead, the names of the record type, predicate, constructor, and so on are all listed explicitly in the source. This has the following advantages:
Type-name, contructor-name, field-tag, and predicate-name are identifiers. Field-spec has one of these two forms:(field-tag accessor-name) (field-tag accessor-name modifier-name)
where field-tag, accessor-name, and modifier-name are each identifiers.
define-record-typeis generative: each use creates a new record type that is distinct from all existing types, including other record types and Scheme's predefined types. Record-type definitions may only occur at top-level (there are two possible semantics for “internal” record-type definitions, generative and nongenerative, and no consensus as to which is better).
An instance of
define-record-typeis equivalent to the following definitions:
- Type-name is bound to a representation of the record type itself. Operations on record types, such as defining print methods, reflection, etc. are left to other SRFIs.
- constructor-name is bound to a procedure that takes as many arguments as there are field-tags in the (constructor-name ...) subform and returns a new type-name record. Fields whose tags are listed with constructor-name have the corresponding argument as their initial value. The initial values of all other fields are unspecified.
- predicate-name is a predicate that returns
#twhen given a value returned by constructor-name and
#ffor everything else.
- Each accessor-name is a procedure that takes a record of type type-name and returns the current value of the corresponding field. It is an error to pass an accessor a value which is not a record of the appropriate type.
- Each modifier-name is a procedure that takes a record of type type-name and a value which becomes the new value of the corresponding field; an unspecified value is returned. It is an error to pass a modifier a first argument which is not a record of the appropriate type.
Assigning the value of any of these identifiers has no effect on the behavior of any of their original values.
(define-record-type :pare (kons x y) pare? (x kar set-kar!) (y kdr))
defines ‘kons’ to be a constructor, ‘kar’ and ‘kdr’ to be accessors, ‘set-kar!’ to be a modifier, and ‘pare?’ to be a predicate for objects of type ‘:pare’.
(pare? (kons 1 2)) ⇒ #t (pare? (cons 1 2)) ⇒ #f (kar (kons 1 2)) ⇒ 1 (kdr (kons 1 2)) ⇒ 2 (let ((k (kons 1 2))) (set-kar! k 3) (kar k)) ⇒ 3