2.3 Record Types
(require rebellion/type/record) | package: rebellion |
A record type is a kind of data type for composite values that contain an unordered set of named fields. The definition of each record type declares how many fields it has and what their names are. Constructing an instance of a record type requires passing a keyword argument for each field to the type’s constructor. Record types are useful when a fixed number of different pieces of data together represent a single logical thing, and there isn’t an obvious order to those pieces.
(define-record-type opcode (name argument addressing-mode)) (define add-42 (opcode #:name 'ADD #:argument 42 #:addressing-mode 'immediate))
> add-42 (opcode #:addressing-mode 'immediate #:argument 42 #:name 'ADD)
> (opcode-name add-42) 'ADD
syntax
(define-record-type id (field-id ...) option ...)
option = #:omit-root-binding | #:descriptor-name descriptor-id | #:predicate-name predicate-id | #:constructor-name constructor-id | #:accessor-name accessor-id | #:pattern-name pattern-id | #:property-maker prop-maker-expr | #:inspector inspector-expr
prop-maker-expr :
(-> uninitialized-record-descriptor? (listof (cons/c struct-type-property? any/c)))
inspector-expr : inspector?
constructor-id, which defaults to constructor:id —
a record constructor that accepts one mandatory keyword argument for each field-id and returns an instance of the created type. predicate-id, which defaults to id? —
a predicate function that returns #t when given instances of the created type and returns #f otherwise. id-field-id for each field-id —
an accessor function that returns the value for field-id when given an instance of the created type. accessor-id, which defaults accessor:id —
a record accessor that accepts an instance of the created type and an integer indicating which field to access, then returns the value of that field. descriptor-id, which defaults to descriptor:id —
the type descriptor for the created type. pattern-id, which defaults to pattern:id —
a match expander that accepts one optional keyword and subpattern pair for each field and deconstructs instances of the created type, matching each field with its corresponding subpattern (if a subpattern for that field is given).
Additionally, unless #:omit-root-binding is specified, the original id is bound to a record type binding for the created type. The binding behaves like pattern-id when used in match patterns and like constructor-id when used as an expression. Use #:omit-root-binding when you want control over what id is bound to, such as when creating a smart constructor.
The prop-maker-expr is used to add structure type properties to the created type, and inspector-expr is used to determine the inspector that will control the created type. See make-record-implementation for more information about these parameters.
(define-record-type color (red green blue)) (define yellow (color #:red 0 #:green 255 #:blue 255))
> yellow (color #:blue 255 #:green 255 #:red 0)
> (color? yellow) #t
> (color-red yellow) 0
> (color-green yellow) 255
> (color-blue yellow) 255
> (match yellow [(color #:red r #:blue b) (list r b)]) '(0 255)
syntax
(define-record-setter record-id maybe-id)
maybe-id =
| id
(define-record-type color (red green blue)) (define-record-setter color) (define yellow (color #:red 0 #:green 255 #:blue 255))
> (color-set yellow #:red 255 #:green 0) (color #:blue 255 #:green 0 #:red 255)
provide transformer
(record-out record)
2.3.1 Record Type Information
procedure
(record-type? v) → boolean?
v : any/c
procedure
(record-type name fields [ #:predicate-name predicate-name #:constructor-name constructor-name #:accessor-name accessor-name]) → record-type? name : symbol? fields : keyset? predicate-name : (or/c symbol? #f) = #f constructor-name : (or/c symbol? #f) = #f accessor-name : (or/c symbol? #f) = #f
procedure
(record-type-name type) → symbol?
type : record-type?
procedure
(record-type-fields type) → keyset?
type : record-type?
procedure
(record-type-predicate-name type) → (or/c symbol? #f)
type : record-type?
procedure
(record-type-constructor-name type) → (or/c symbol? #f)
type : record-type?
procedure
(record-type-accessor-name type) → (or/c symbol? #f)
type : record-type?
2.3.2 Record Type Descriptors
Record types are implemented using structs, where the fields of the struct are always sorted by name. The type descriptor for a record type contains two functions that implement the type:
A record constructor that accepts a mandatory keyword argument for each field of the record type and constructs a record instance.
A record accessor that accepts an instance of the record type and an integer field index, then returns the value of the corresponding field. Record fields are always sorted alphabetically, and the field index corresponding to a given field name can be retrieved from the record type using the record-type-fields keyset.
These functions can be used to dynamically construct and inspect instances of arbitrary record types at runtime, assuming the type’s descriptor is initialized. Note that the descriptor contains a single accessor function that can access any field in the record: the per-field accessors created by define-record-type are merely convenient wrappers around this accessor.
procedure
(record-descriptor? v) → boolean?
v : any/c
procedure
v : any/c
procedure
v : any/c
procedure
(make-record-implementation type [ #:inspector inspector #:property-maker prop-maker]) → initialized-record-descriptor? type : record-type? inspector : inspector? = (current-inspector)
prop-maker :
(-> uninitialized-record-descriptor? (listof (cons/c struct-type-property? any/c))) = default-record-properties
procedure
(record-descriptor-type descriptor) → record-type?
descriptor : record-descriptor?
procedure
(record-descriptor-predicate descriptor) → predicate/c
descriptor : record-descriptor?
procedure
(record-descriptor-constructor descriptor) → procedure?
descriptor : record-descriptor?
procedure
(record-descriptor-accessor descriptor)
→ (-> (record-descriptor-predicate descriptor) natural? any/c) descriptor : record-descriptor?
procedure
(make-record-field-accessor descriptor field) → (-> (record-descriptor-predicate descriptor) any/c) descriptor : record-descriptor? field : natural?
procedure
(default-record-properties descriptor)
→ (listof (cons/c struct-type-property? any/c)) descriptor : record-descriptor?
procedure
(default-record-equal+hash descriptor) → equal+hash/c
descriptor : record-descriptor?
procedure
(default-record-custom-write descriptor)
→ custom-write-function/c descriptor : record-descriptor?
2.3.3 Record Type Bindings
(require rebellion/type/record/binding) | package: rebellion |
A record type binding is a type binding for a record type. Record type bindings contain compile-time information about the record type’s name and fields, as well as runtime bindings for its predicate, type descriptor, and other runtime components. To extract a record type binding bound by define-record-type, use the record-id syntax class.
procedure
(record-binding? v) → boolean?
v : any/c
syntax class
type —
an attribute bound to a compile-time record-type? value describing the type. binding —
an attribute bound to the compile-time record-binding? value extracted from the matched identifier. name —
a pattern variable bound to the record type’s name, as a quoted symbol. descriptor —
a pattern variable bound to the record type’s runtime type descriptor. predicate —
a pattern variable bound to the record type’s runtime type predicate. constructor —
a pattern variable bound to the record type’s runtime record constructor. accessor —
a pattern variable bound to the record type’s runtime record accessor. field ... —
a pattern variable bound to the record’s fields, as plain identifiers. field-name ... —
a pattern variable bound to the record’s field names, as quoted symbols. field-keyword ... —
a pattern variable bound to the record’s field names, as keywords. field-accessor ... —
a pattern variable bound to the record type’s per-field runtime field accessors.
(require (for-syntax rebellion/type/record/binding)) (define-simple-macro (record-field-names record:record-id) (list record.field-name ...)) (define-record-type email (subject author body))
> (record-field-names email) '(author body subject)
procedure
(record-binding-type binding) → record-type?
binding : record-binding?
procedure
(record-binding-descriptor binding) → identifier?
binding : record-binding?
procedure
(record-binding-predicate binding) → identifier?
binding : record-binding?
procedure
(record-binding-constructor binding) → identifier?
binding : record-binding?
procedure
(record-binding-accessor binding) → identifier?
binding : record-binding?
procedure
(record-binding-fields binding)
→ (vectorof identifier? #:immutable #t) binding : record-binding?
procedure
(record-binding-field-accessors binding)
→ (vectorof identifier? #:immutable #t) binding : record-binding?