LispPad

Lightweight Scheme Development on macOS

LispKit Record

Library (lispkit record) implements record types for LispKit. A record provides a simple and flexible mechanism for building structures with named components wrapped in distinct types.

Declarative API

record-type syntax is used to introduce new record types in a declarative fashion. Like other definitions, record-type can either appear at the outermost level or locally within a body. The values of a record type are called records and are aggregations of zero or more fields, each of which holds a single location. A predicate, a constructor, and field accessors and mutators are defined for each record type.

(define-record-type <name> <constr> <pred> <field> ...) [syntax]

<name> and <pred> are identifiers. The <constructor> is of the form:

   (<constructor name> <field name> ...)

and each <field> is either of the form:

   (<field name> <accessor name>), or
   (<field name> <accessor name> <modifier name>).

It is an error for the same identifier to occur more than once as a field name. It is also an error for the same identifier to occur more than once as an accessor or mutator name.

The define-record-type construct is generative: each use creates a new record type that is distinct from all existing types, including the predefined types and other record types - even record types of the same name or structure.

An instance of define-record-type is equivalent to the following definitions:

  • <name> is bound to a representation of the record type itself.

  • <constructor name> is bound to a procedure that takes as many arguments as there are <field name> elements in the (<constructor name> ...) subexpression and returns a new record of type <name>. Fields whose names are listed with <constructor name> have the corresponding argument as their initial value. The initial values of all other fields are unspecified. It is an error for a field name to appear in <constructor> but not as a <field name>.

  • <pred> is bound to a predicate that returns #t when given a value returned by the procedure bound to <constructor name> and #f for everything else.

  • Each <accessor name> is bound to a procedure that takes a record of 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 bound to a procedure that takes a record of type <name> and a value which becomes the new value of the corresponding field. It is an error to pass a modifier a first argument which is not a record of the appropriate type.

For instance, the following record-type definition:


(define-record-type 
  (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 type predicate for instances of <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

Procedural API

Besides the syntactical define-record-type abstraction for defining record types in a declarative fashion, LispKit provides a low-level, procedural API for creating and instantiating records and record types. Record types are represented in form of record type descriptor objects which itself are records.

(record? obj) [procedure]

Returns #t if obj is a record of any type; returns #f otherwise.

(record-type? obj) [procedure]

Returns #t if obj is a record type descriptor; returns #f otherwise.

(record-type obj) [procedure]

Returns the record type descriptor for objects obj which are records; returns #f for all non-record values.

(make-record-type name fields) [procedure]

Returns a record type descriptor which represents a new data type that is disjoint from all other types. name is a string which is only used for debugging purposes, such as the printed representation of a record of the new type. fields is a list of symbols naming the fields of a record of the new type. It is an error if the list contains duplicate symbols.

(record-type-name rtd) [procedure]

Returns the type name (a string) associated with the type represented by the record type descriptor rtd. The returned value is eqv? to the name argument given in the call to make-record-type that created the type represented by rtd.

(record-type-field-names rtd) [procedure]

Returns a list of the symbols naming the fields in members of the type represented by the record type descriptor rtd. The returned value is equal? to the fields argument given in the call to make-record-type that created the type represented by rtd.

(make-record rtd) [procedure]

Returns an uninitialized instance of the record type for which rtd is the record type descriptor.

(record-constructor rtd fields) [procedure]

Returns a procedure for constructing new members of the type represented by the record type descriptor rtd. The returned procedure accepts exactly as many arguments as there are symbols in the given fields list; these are used, in order, as the initial values of those fields in a new record, which is returned by the constructor procedure. The values of any fields not named in fields are unspecified. It is an error if fields contain any duplicates or any symbols not in the fields list of the record type descriptor rtd.

(record-predicate rtd) [procedure]

Returns a procedure for testing membership in the type represented by the record type descriptor rtd. The returned procedure accepts exactly one argument and returns #t if the argument is a member of the indicated record type; it returns #f otherwise.

(record-field-accessor rtd field) [procedure]

Returns a procedure for reading the value of a particular field of a member of the type represented by the record type descriptor rtd. The returned procedure accepts exactly one argument which must be a record of the appropriate type; it returns the current value of the field named by the symbol field in that record. The symbol field must be a member of the list of field names in the call to make-record-type that created the type represented by rtd.

(record-field-mutator rtd field) [procedure]

Returns a procedure for writing the value of a particular field of a member of the type represented by the record type descriptor rtd. The returned procedure accepts exactly two arguments: first, a record of the appropriate type, and second, an arbitrary Scheme value; it modifies the field named by the symbol field in that record to contain the given value. The returned value of the modifier procedure is unspecified. The symbol field must be a member of the list of field names in the call to make-record-type that created the type represented by rtd.