5.7 Structure Type Transformer Binding
The struct form binds the name of a structure type as a transformer binding that records the other identifiers bound to the structure type, the constructor procedure, the predicate procedure, and the field accessor and mutator procedures. This information can be used during the expansion of other expressions via syntax-local-value.
For example, the struct variant for subtypes uses the base type name t to find the variable struct:t containing the base type’s descriptor; it also folds the field accessor and mutator information for the base type into the information for the subtype. As another example, the match form uses a type name to find the predicates and field accessors for the structure type. The struct form in an imported signature for unit causes the unit transformer to generate information about imported structure types, so that match and subtyping struct forms work within the unit.
The expansion-time information for a structure type can be represented directly as a list of six elements (of the same sort that the encapsulated procedure must return):
an identifier that is bound to the structure type’s descriptor, or #f if none is known;
an identifier that is bound to the structure type’s constructor, or #f if none is known;
an identifier that is bound to the structure type’s predicate, or #f if none is known;
a list of identifiers bound to the field accessors of the structure type, optionally with #f as the list’s last element. A #f as the last element indicates that the structure type may have additional fields, otherwise the list is a reliable indicator of the number of fields in the structure type. Furthermore, the accessors are listed in reverse order for the corresponding constructor arguments. (The reverse order enables sharing in the lists for a subtype and its base type.)
a list of identifiers bound to the field mutators of the structure type, or #f for each field that has no known mutator, and optionally with an extra #f as the list’s last element (if the accessor list has such a #f). The list’s order and the meaning of a final #f are the same as for the accessor identifiers, and the length of the mutator list is the same as the accessor list’s length.
an identifier that determines a super-type for the structure type, #f if the super-type (if any) is unknown, or #t if there is no super-type. If a super-type is specified, the identifier is also bound to structure-type expansion-time information.
Instead of this direct representation, the representation can be a structure created by make-struct-info (or an instance of a subtype of struct:struct-info), which encapsulates a procedure that takes no arguments and returns a list of six elements. Alternately, the representation can be a structure whose type has the prop:struct-info structure type property. Finally, the representation can be an instance of a structure type derived from struct:struct-info or with the prop:struct-info property that also implements prop:procedure, and where the instance is further is wrapped by make-set!-transformer. In addition, the representation may implement the prop:struct-auto-info property.
Use struct-info? to recognize all allowed forms of the information, and use extract-struct-info to obtain a list from any representation.
The implementor of a syntactic form can expect users of the form to know what kind of information is available about a structure type. For example, the match implementation works with structure information containing an incomplete set of accessor bindings, because the user is assumed to know what information is available in the context of the match expression. In particular, the match expression can appear in a unit form with an imported structure type, in which case the user is expected to know the set of fields that are listed in the signature for the structure type.
(require racket/struct-info) | package: base |
procedure
(struct-info? v) → boolean?
v : any/c
procedure
(checked-struct-info? v) → boolean?
v : any/c
procedure
(make-struct-info thunk) → struct-info?
thunk : (-> (and/c struct-info? list?))
> (define (new-pair? x) (displayln "new pair?") (pair? x))
> (define (new-car x) (displayln "new car") (car x))
> (define (new-cdr x) (displayln "new cdr") (cdr x))
> (define-syntax new-list (make-struct-info (λ () (list #f #'cons #'new-pair? (list #'new-cdr #'new-car) (list #f #f) #t))))
> (match (list 1 2 3) [(new-list hd tl) (append tl (list hd))])
new pair?
new car
new cdr
'(2 3 1)
> (struct A (x y))
> (define (new-A-x a) (displayln "A-x") (A-x a))
> (define (new-A-y a) (displayln "A-y") (A-y a))
> (define (new-A? a) (displayln "A?") (A? a))
> (define-syntax A-info (make-struct-info (λ () (list #'A #'A #'new-A? (list #'new-A-y #'new-A-x) (list #f #f) #t))))
> (define-match-expander B (syntax-rules () [(_ x ...) (A-info x ...)]))
> (match (A 10 20) [(B x y) (list y x)])
A?
A-x
A-y
'(20 10)
procedure
(extract-struct-info v) → (and/c struct-info? list?)
v : struct-info?
value
value
procedure
(struct-auto-info? v) → boolean?
v : any/c
procedure
(struct-auto-info-lists sai)
→ (list/c (listof identifier?) (listof identifier?)) sai : struct-auto-info?
The struct-auto-info? predicate recognizes values that implement the prop:struct-auto-info property.
The struct-auto-info-lists function extracts two lists of identifiers from a value that implements the prop:struct-auto-info property. The first list should be a subset of the accessor identifiers for the structure type described by sai, and the second list should be a subset of the mutator identifiers. The two subsets correspond to #:auto fields.