This section provides examples and describes the options and syntax of
define-structure, an MIT/GNU Scheme macro that is very similar to
defstruct in Common Lisp. The differences between them are
summarized at the end of this section. For more information, see
Steele's Common Lisp book.
Each slot-description takes one of the following forms:slot-name (slot-name default-init [slot-option value]*)
The fields name and slot-name must both be symbols. The field default-init is an expression for the initial value of the slot. It is evaluated each time a new instance is constructed. If it is not specified, the initial content of the slot is undefined. Default values are only useful with a boa constructor with argument list or a keyword constructor (see below).
Evaluation of a
define-structureexpression defines a structure descriptor and a set of procedures to manipulate instances of the structure. These instances are represented as records by default (see Records) but may alternately be lists or vectors. The accessors and modifiers are marked with compiler declarations so that calls to them are automatically transformed into appropriate references. Often, no options are required, so a simple call to
define-structurelooks like:(define-structure foo a b c)
This defines a type descriptor
rtd:foo, a constructor
make-foo, a predicate
foo-c, and modifiers
In general, if no options are specified,
define-structuredefines the following (using the simple call above as an example):
- type descriptor
- The name of the type descriptor is
"rtd:"followed by the name of the structure, e.g. ‘rtd:foo’. The type descriptor satisfies the predicate
- The name of the constructor is
"make-"followed by the name of the structure, e.g. ‘make-foo’. The number of arguments accepted by the constructor is the same as the number of slots; the arguments are the initial values for the slots, and the order of the arguments matches the order of the slot definitions.
- The name of the predicate is the name of the structure followed by
"?", e.g. ‘foo?’. The predicate is a procedure of one argument, which returns
#tif its argument is a record of the type defined by this structure definition, and
- For each slot, an accessor is defined. The name of the accessor is formed by appending the name of the structure, a hyphen, and the name of the slot, e.g. ‘foo-a’. The accessor is a procedure of one argument, which must be a record of the type defined by this structure definition. The accessor extracts the contents of the corresponding slot in that record and returns it.
- For each slot, a modifier is defined. The name of the modifier is formed by appending
"set-", the name of the accessor, and
"!", e.g. ‘set-foo-a!’. The modifier is a procedure of two arguments, the first of which must be a record of the type defined by this structure definition, and the second of which may be any object. The modifier modifies the contents of the corresponding slot in that record to be that object, and returns an unspecified value.
When options are not supplied,
)may be abbreviated to name. This convention holds equally for structure-options and slot-options. Hence, these are equivalent:(define-structure foo a b c) (define-structure (foo) (a) b (c))
as are(define-structure (foo keyword-constructor) a b c) (define-structure (foo (keyword-constructor)) a b c)
When specified as option values,
nilare equivalent to
tare equivalent to
Possible slot-options are:
When given a value other than
#f, this specifies that no modifier should be created for the slot.
Possible structure-options are:
This option controls the definition of a predicate procedure for the structure. If name is not given, the predicate is defined with the default name (see above). If name is
#f, the predicate is not defined at all. Otherwise, name must be a symbol, and the predicate is defined with that symbol as its name.
This option controls the definition of a procedure to copy instances of the structure. This is a procedure of one argument, a structure instance, that makes a newly allocated copy of the structure and returns it. If name is not given, the copier is defined, and the name of the copier is
"copy-"followed by the structure name (e.g. ‘copy-foo’). If name is
#f, the copier is not defined. Otherwise, name must be a symbol, and the copier is defined with that symbol as its name.
Evaluating expression must yield a procedure of two arguments, which is used to print instances of the structure. The procedure is an unparser method (see Custom Output). If the structure instances are records, this option has the same effect as calling
This option controls the definition of constructor procedures. These constructor procedures are called “boa constructors”, for “By Order of Arguments”, because the arguments to the constructor specify the initial contents of the structure's slots by the order in which they are given. This is as opposed to “keyword constructors”, which specify the initial contents using keywords, and in which the order of arguments is irrelevant.
If name is not given, a constructor is defined with the default name and arguments (see above). If name is
#f, no constructor is defined; argument-list may not be specified in this case. Otherwise, name must be a symbol, and a constructor is defined with that symbol as its name. If name is a symbol, argument-list is optionally allowed; if it is omitted, the constructor accepts one argument for each slot in the structure definition, in the same order in which the slots appear in the definition. Otherwise, argument-list must be a lambda list (see Lambda Expressions), and each of the parameters of the lambda list must be the name of a slot in the structure. The arguments accepted by the constructor are defined by this lambda list. Any slot that is not specified by the lambda list is initialized to the default-init as specified above; likewise for any slot specified as an optional parameter when the corresponding argument is not supplied.
constructoroption is specified, the default constructor is not defined. Additionally, the
constructoroption may be specified multiple times to define multiple constructors with different names and argument lists.(define-structure (foo (constructor make-foo (#!optional a b))) (a 6 read-only #t) (b 9))
This option controls the definition of keyword constructor procedures. A keyword constructor is a procedure that accepts arguments that are alternating slot names and values. If name is omitted, a keyword constructor is defined, and the name of the constructor is
"make-"followed by the name of the structure (e.g. ‘make-foo’). Otherwise, name must be a symbol, and a keyword constructor is defined with this symbol as its name.
keyword-constructoroption is specified, the default constructor is not defined. Additionally, the
keyword-constructoroption may be specified multiple times to define multiple keyword constructors; this is usually not done since such constructors would all be equivalent.(define-structure (foo (keyword-constructor make-bar)) a b) (foo-a (make-bar 'b 20 'a 19)) ⇒ 19
This option cannot be used with the
By default, structures are implemented as records. The name of the structure is defined to hold the type descriptor of the record defined by the structure. The
type-descriptoroption specifies a different name to hold the type descriptor.(define-structure foo a b) foo ⇒ #[record-type 18] (define-structure (bar (type-descriptor <bar>)) a b) bar error--> Unbound variable: bar <bar> ⇒ #[record-type 19]
By default, the prefix for naming accessors and modifiers is the name of the structure followed by a hyphen. The
conc-nameoption can be used to specify an alternative. If name is not given, the prefix is the name of the structure followed by a hyphen (the default). If name is
#f, the slot names are used directly, without prefix. Otherwise, name must a symbol, and that symbol is used as the prefix.
(define-structure (foo (conc-name moby/)) a b)
moby/b, and modifiers
(define-structure (foo (conc-name #f)) a b)
b, and modifiers
This option cannot be used with the
By default, structures are implemented as records. The
typeoption overrides this default, allowing the programmer to specify that the structure be implemented using another data type. The option value representation-type specifies the alternate data type; it is allowed to be one of the symbols
list, and the data type used is the one corresponding to the symbol.
If this option is given, and the
namedoption is not specified, the representation will not be tagged, and neither a predicate nor a type descriptor will be defined; also, the
print-procedureoption may not be given.(define-structure (foo (type list)) a b) (make-foo 1 2) ⇒ (1 2)
This is valid only in conjunction with the
typeoption and specifies that the structure instances be tagged to make them identifiable as instances of this structure type. This option cannot be used with the
In the usual case, where expression is not given, the
namedoption causes a type descriptor and predicate to be defined for the structure (recall that the
namedsuppresses their definition), and also defines a default unparser method for the structure instances (which can be overridden by the
print-procedureoption). If the default unparser method is not wanted then the
print-procedureoption should be specified as
#F. This causes the structure to be printed in its native representation, as a list or vector, which includes the type descriptor. The type descriptor is a unique object, not a record type, that describes the structure instances and is additionally stored in the structure instances to identify them: if the representation type is
vector, the type descriptor is stored in the zero-th slot of the vector, and if the representation type is
list, it is stored as the first element of the list.(define-structure (foo (type vector) named) a b c) (vector-ref (make-foo 1 2 3) 0) ⇒ #[structure-type 52]
If expression is specified, it is an expression that is evaluated to yield a tag object. The expression is evaluated once when the structure definition is evaluated (to specify the unparser method), and again whenever a predicate or constructor is called. Because of this, expression is normally a variable reference or a constant. The value yielded by expression may be any object at all. That object is stored in the structure instances in the same place that the type descriptor is normally stored, as described above. If expression is specified, no type descriptor is defined, only a predicate.(define-structure (foo (type vector) (named 'foo)) a b c) (vector-ref (make-foo 1 2 3) 0) ⇒ foo
This option allows the programmer to have some control over the safety of the slot accessors (and modifiers) generated by
safe-accessorsis not specified, or if boolean is
#f, then the accessors are optimized for speed at the expense of safety; when compiled, the accessors will turn into very fast inline sequences, usually one to three machine instructions in length. However, if
safe-accessorsis specified and boolean is either omitted or
#t, then the accessors are optimized for safety, will check the type and structure of their argument, and will be close-coded.(define-structure (foo safe-accessors) a b c)
This is valid only in conjunction with the
typeoption. Offset must be an exact non-negative integer and specifies the number of slots to leave open at the beginning of the structure instance before the specified slots are allocated. Specifying an offset of zero is equivalent to omitting the
namedoption is specified, the structure tag appears in the first slot, followed by the “offset” slots, and then the regular slots. Otherwise, the “offset” slots come first, followed by the regular slots.(define-structure (foo (type vector) (initial-offset 3)) a b c) (make-foo 1 2 3) ⇒ #(() () () 1 2 3)
The essential differences between MIT/GNU Scheme's
and Common Lisp's
&auxin Scheme lambda lists, this functionality is not implemented.
copierprocedure is defined.
foois given the name
tare treated as if the appropriate boolean constant had been specified instead.
print-functionoption is named
print-procedure. Its argument is a procedure of two arguments (the unparser state and the structure instance) rather than three as in Common Lisp.
namedoption may optionally take an argument, which is normally the name of a variable (any expression may be used, but it is evaluated whenever the tag name is needed). If used, structure instances will be tagged with that variable's value. The variable must be defined when
typeoption is restricted to the values
includeoption is not implemented.