# (lispkit record)

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.

## 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.

### Syntax

**(define-record-type&#x20;*****\<type> \<constr> \<pred> \<field> ...*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-1f16bffbe68f0214f8ffbb3b3230748db5570827%2Fsyntax.png?alt=media" alt="" data-size="line">

*\<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:

&#x20;    *\<type name>*, or\
&#x20;    (*\<type name> \<supertype>*).

The *\<constructor>* is of one of the two possible forms:

&#x20;    *\<constructor name>, or*\
&#x20;    *(*\<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:

&#x20;  (*\<field name> \<accessor name>*), or\
&#x20;  (*\<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.

### Examples

The following record-type definition:

```scheme
(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 type predicate for instances of `<pare>`.

```scheme
(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
```

Below is another example showcasing how record types can be extended. First a new record type `<point>` is defined:

```scheme
(define-record-type <point>
  (make-point x y)
  point?
  (x point-x set-point-x!)
  (y point-y set-point-y!))
```

Next, a new record type `<color-point>` is defined to extend record type `<point>`:

```scheme
(define-record-type (<color-point> <point>)
  (make-color-point x y color)
  color-point?
  (color point-color))
```

The following transcript shows that `<color-point>` objects are also considered `<point>` objects which inherit all fields from `<point>`:

```scheme
(define cp (make-color-point 12 3 red))
(color-point? cp)    ⇒  #t
(point? cp)          ⇒  #t
(color-point?
  (make-point 1 2))  ⇒  #f
(point-x cp)         ⇒  12
(set-point-x! cp 1)
(point-x cp)         ⇒  1
(point-color cp)     ⇒  #<color 1.0 0.0 0.0>
```

## 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?&#x20;*****obj*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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

**(record-type?&#x20;*****obj*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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

**(record-type&#x20;*****obj*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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

**(make-record-type&#x20;*****name fields*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(make-record-type&#x20;*****name fields parent*****)**

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.

**(record-type-name&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(record-type-field-names&#x20;*****rtd all?*****)**

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.

**(record-type-parent&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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.

**(record-type-field-index&#x20;*****rtd field*****)**  <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(record-type-field-index&#x20;*****rtd fields*****)**

Returns the zero-based index of the given *field* (a symbol) within the record type represented by record type descriptor *rtd*. If *fields* is a list of symbols, returns a list of corresponding indices. This procedure is useful for implementing efficient field access. It is an error if *field* is not a field name of the record type.

**(record-type-tag&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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)`.

**(make-record&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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

**(record-ref&#x20;*****record index*****)**    <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(record-ref&#x20;*****record index rtd*****)**

Returns the value of the field at zero-based *index* in *record*. If *rtd* (a record type descriptor) is provided, verifies that *record* is of the specified type. It is an error if *index* is out of bounds or if *record* is not of the appropriate type.

**(record-set!&#x20;*****record index value*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(record-set!&#x20;*****record index value rtd*****)**\
\&#xNAN;**(record-set!&#x20;*****record indices values*****)**\
\&#xNAN;**(record-set!&#x20;*****record indices values rtd*****)**

Sets the field at zero-based *index* in *record* to *value*. If *rtd* (a record type descriptor) is provided, verifies that *record* is of the specified type. If *indices* is a list of indices and *values* is a list of values, sets multiple fields at once. It is an error if any index is out of bounds, if *record* is not of the appropriate type, or if *record* is immutable.

**(record-constructor&#x20;*****rtd fields*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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&#x20;*****rtd*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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&#x20;*****rtd field*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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&#x20;*****rtd field*****)**   <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

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*.
