(lispkit record)
Last updated
Last updated
Library (lispkit record)
implements extensible record types for LispKit which are compatible with R7RS and SRFI 131. A record provides a simple and flexible mechanism for building structures with named components wrapped in distinct types.
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 <type> <constr> <pred> <field> ...)
<type> defines the name of the new record type and potentially the supertype if the new type is an extension of an existing record type. Thus, it has one of the two possible forms, where <type name> is an identifier and <supertype> an arbitrary expression evaluating to a record type descriptor:
<type name>, or (<type name> <supertype>).
The <constructor> is of one of the two possible forms:
<constructor name>, or (<constructor name> <field name> ..._)
When a constructor is of the form (<constructor name> <field name> ...), the following holds:
Each of the field names can be either a field name declared in the same define-record-type
form, or any of its ancestors' field names.
If the record definition contains the same field name as one of its ancestors, it shadows the ancestor's field name for the purposes of the constructor. The constructor's argument initializes the child's slot, and the ancestor's slot of the same name is left uninitialized.
It is an error if the same identifier appears more than once in the field names of the constructor spec.
<pred> is the identifier denoting the type predicate that recognizes instances of the new record type and its subtypes. 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:
<type name> is bound to a representation of the record type itself. If a <supertype> expression is specified, then it must evaluate to a record type descriptor that serves as the parent record type for the record type being defined.
<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> or any constructor of a subtype. It returns #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.
The following record-type definition:
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>
.
Below is another example showcasing how record types can be extended. First a new record type <point>
is defined:
Next, a new record type <color-point>
is defined to extend record type <point>
:
The following transcript shows that <color-point>
objects are also considered <point>
objects which inherit all fields from <point>
:
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.
Returns #t
if obj is a record of any type; returns #f
otherwise.
Returns #t
if obj is a record type descriptor; returns #f
otherwise.
Returns the record type descriptor for objects obj which are records; returns #f
for all non-record values.
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. parent refers to a record type descriptor for the supertype of the newly created record type. By default, parent is #f
, i.e. the new record type does not have a parent type.
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.
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. If boolean argument all? is true (default is false), then a list of all symbols, also defined by parent types of rtd, is returned.
Returns a record type descriptor for the parent type of the record type represented by the record type descriptor rtd. record-type-parent
returns #f
if rtd does not have a parent type.
Returns the type tag, i.e. an uninterned symbol, representing the type of records defined by rtd. The result of record-type-tag
can be used together with procedure type-of
of library (lispkit type)
.
Returns an uninitialized instance of the record type for which rtd is the record type descriptor.
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.
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.
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.
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.
(record? obj)
(record-type? obj)
(record-type obj)
(make-record-type name fields) (make-record-type name fields parent)
(record-type-name rtd)
(record-type-field-names rtd) (record-type-field-names rtd all?)
(record-type-parent rtd)
(record-type-tag rtd)
(make-record rtd)
(record-constructor rtd fields)
(record-predicate rtd)
(record-field-accessor rtd field)
(record-field-mutator rtd field)