![]()
|
PLT MzScheme: Language Manual
|
(lambda (s) (accessor-proc s field-pos-k)) |
accessor-proc
must be an accessor returned by
make-struct-type
. The name of the resulting procedure for
debugging purposes is derived from field-name-symbol
and
the name of accessor-proc
's structure type.
(make-struct-field-mutator
mutator-proc field-pos-k field-name-symbol
)
returns a field mutator that is equivalent to
(lambda (s v) (mutator-proc s field-pos-k v)) |
mutator-proc
must be a mutator returned by
make-struct-type
. The name of the resulting procedure for
debugging purposes is derived from field-name-symbol
and
the name of mutator-proc
's structure type.
Examples:
(define-values (struct:a make-a a? a-ref a-set!) (make-struct-type
'a #f 2 1 'uninitialized)) (define an-a (make-a 'x 'y)) (a-ref an-a 1) ; =>'y
(a-ref an-a 2) ; =>'uninitialized
(define a-first (make-struct-field-accessor
a-ref 0)) (a-first an-a) ; =>'x
If an integer or procedure is provided as the proc-spec
argument
to make-struct-type
(see section 4.3),
instances of the new structure type are procedures. In particular,
when procedure?
is applied to the instance, the result
will be #t
. When an instance is used in the function
position of an application expression, a procedure is extracted from
the instance and used to complete the procedure call.
If proc-spec
is an integer, it designates a field within the
structure that should contain a procedure. The proc-spec
integer must be between 0 (inclusive) and
init-field-k
+ auto-field-k
(exclusive).
The designated field becomes immutable, so that after an instance of
the structure is created, its procedure cannot be
changed. (Otherwise, the arity and name of the instance could change,
and such mutations are generally not allowed for procedures.) When
the instance is used as the procedure in an application expression,
the value of the designated field in the instance is used to complete
the procedure call.6 That
procedure receives all of the arguments from the application
expression. The procedure's name (see section 6.2.4) and arity
(see section 3.10.1) are also used for the name and arity of the
structure. If the value in the designated field is not a procedure,
then the instance behaves like (case-lambda)
(i.e., a
procedure which does not accept any number of arguments).
Example:
(define-values (struct:ap make-annotated-proc annotated-proc? ap-ref ap-set!) (make-struct-type
'anotated-proc #f 2 0 #fnull
#f 0)) (define (proc-annotation p) (ap-ref p 1)) (define plus1 (make-annotated-proc (lambda (x) (+ x 1)) "adds 1 to its argument")) (procedure?
plus1) ; =>#t
(annotated-proc? plus1) ; =>#t
(plus1 10) ; =>11
(proc-annotation plus1) ; =>"adds 1 to its argument"
If proc-spec
is a procedure, it should accept at least one
argument. When an instance of the structure is used in an application
expression, the proc-spec
procedure is called with the instance
as the first argument. The remaining arguments to the proc-spec
procedure are the arguments from the application expression. Thus, if
the application expression contained five arguments, proc-spec
is called with six arguments. The name of the instance (see
section 6.2.4) is unaffected by proc-spec
, but the
instance's arity is determined by subtracting one from every possible
argument count of proc-spec
. If proc-spec
cannot accept
at least one argument, then the instance behaves like
(case-lambda)
.
(define-values (struct:fish make-fish fish? fish-ref fish-set!) (make-struct-type
'fish #f 2 0 #fnull
#f (lambda (f n) (fish-set! f 0 (+ n (fish-ref f 0)))))) (define (fish-weight f) (fish-ref f 0)) (define (fish-color f) (fish-ref f 1)) (define wanda (make-fish 12 'red)) (fish? wanda) ; =>#t
(procedure?
wanda) ; =>#t
(fish-weight wanda) ; =>12
(for-each
wanda '(1 2 3)) (fish-weight wanda) ; =>18
If a structure type generates procedure instances, then subtypes of
the type also generate procedure instances. The instances behave the
same as instances of the original type, unless the subtype creation
also specifies a proc-spec
, in which case the
proc-spec
``overrides'' the procedure behavior of the base
type.
A structure type property
allows per-type information to be associated with a structure type
(as opposed to per-instance information associated with a structure
value). A property value is associated with a structure type through
the
procedure (see
section 4.3). Subtypes inherit the property values
of their parent types, and only one value can be associated with a
type for any property.make-struct-type
(make-struct-type-property
name-symbol
)
creates a new structure
type property and returns three values:
a structure property type descriptor, for use with
;make-struct-type
a predicate procedure, which takes an arbitrary value and
returns #t
if the value is a descriptor or instance of a
structure type that has a value for the property, #f
otherwise;
an accessor procedure, which returns the value associated with
structure type given its descriptor or one of its instances; the
structure type does not have a value for the property, or if any
other kind of value is provided, the exn:application:type
exception is raised.
(struct-type-property?
v
)
returns #t
if v
is a
structure type property descriptor value, #f
otherwise.
Examples:
(define-values (prop:p p? p-ref) (make-struct-type-property
'p)) (define-values (struct:a make-a a? a-ref a-set!) (make-struct-type
'a #f 2 1 'uninitialized (list
(cons
prop:p 8)))) (p? struct:a) ; =>#t
(p? 13) ; =>#f
(define an-a (make-a 'x 'y)) (p? an-a) ; =>#t
(p-ref an-a) ; =>8
(define-values (struct:b make-b b? b-ref b-set!) (make-struct-type
'b #f 0 0 #f)) (p? struct:b) ; =>#f
An inspector provides access to structure fields and structure type information without the normal field accessors and mutators. Inspectors are primarily intended for use by debuggers.
When a structure type is created, an inspector can be supplied. The given inspector is not the one that will control the new structure type; instead, the given inspector's parent will control the type. By using the parent of the given inspector, the structure type remains opaque to ``peer'' code that cannot access the parent inspector. Thus, an expression of the form
(define-struct s (field ···))
creates a structure type whose instances are opaque to peer code. In contrast, the following idiom creates a structure type that is transparent to peer code, because the supplied inspector is a newly created child of the current inspector:
(define-struct s (field ···) (make-inspector
))
The
parameter determines a default inspector
argument for new structure types. An alternate inspector can be
provided though the optional current-inspector
inspector-expr
expression of the
define-struct
form (see section 4.1), as shown
above, or through an optional inspector
argument to
(see section 4.3).make-struct-type
(make-inspector
[inspector
])
returns a new inspector that is a
subinspector of inspector
. If inspector
is not provided,
the new inspector is a subinspector of the current inspector. Any
structure type controlled by the new inspector is also controlled by
its ancestor inspectors, but no other inspectors.
(inspector?
v
)
returns #t
if v
is an inspector,
#f
otherwise.
The
and struct-info
procedures provide
inspector-based access to structure and structure type information:struct-type-info
(struct-info
v
)
returns two values:
struct-type
: a structure type descriptor or #f
;
the result is a structure type descriptor of the most specific type
for which v
is an instance, and for which the current
inspector has control, or the result is #f
if the current
inspector does not control any structure type for which the
struct
is an instance.
skipped?
: #f
if the first result corresponds to
the most specific structure type of v
, #t
otherwise.
(struct-type-info
struct-type
)
returns six values that
provide information about the structure type descriptor
struct-type
, assuming that the type is controlled by the
current inspector:
name-symbol
: the structure type's name as a symbol;
field-k
: the number of fields defined by the structure type (not
counting fields created by its ancestor types);
accessor-proc
: an accessor procedure for the structure type,
like the one returned by
;make-struct-type
mutator-proc
: a mutator procedure for the structure type, like the one
returned by
;make-struct-type
super-struct-type
: a structure type descriptor for the
most specific ancestor of the type that is controlled by the
current inspector, or #f
if no ancestor is controlled by
the current inspector;
skipped?
: #f
if the fifth result is the most
specific ancestor type or if the type has no supertype, #t
otherwise.
If the type for struct-type
is not controlled by the current inspector,
the exn:application:mismatch
exception is raised.
The following utility procedures work on all structure instances:
(struct->vector
v
[opaque-v
])
creates a vector representing
v
. The first slot of the result vector contains a symbol of
the form struct:
. The each remaining slot contains
either the value of a field in s
v
if it is accessible via the
current inspector, or opaque-v
for a field that is not
accessible. A single opaque-v
value is used in the vector for
contiguous inaccessible fields. (Consequently, the size of the vector
does not match the size of the struct
if more than one field is
inaccessible.) The symbol '...
is the default value for
opaque-v
.
(struct?
v
)
returns #t
if struct->vector
exposes any fields of v
with the current inspector, #f
otherwise.
Two structure values are eqv?
if and only if they are
eq?
. Two structure values are equal?
if and
only if they are instances of the same structure type, no fields are
opaque, and the results of applying
to the
structs are struct->vector
. (Consequently, equal?
testing
for structures depends on the current inspector.)equal?
Each kind of value returned by define-struct
and
has a recognizing predicate:
make-struct-type
(struct-type?
v
)
returns #t
if v
is a
structure type descriptor value, #f
otherwise.
(struct-constructor-procedure?
v
)
returns #t
if
v
is a constructor procedure generated by define-struct
or
, make-struct-type
#f
otherwise.
(struct-predicate-procedure?
v
)
returns #t
if
v
is a predicate procedure generated by define-struct
or
, make-struct-type
#f
otherwise.
(struct-accessor-procedure?
v
)
returns #t
if v
is an accessor procedure generated by define-struct
,
, or make-struct-type
,
make-struct-field-accessor
#f
otherwise.
(struct-mutator-procedure?
v
)
returns #t
if v
is a mutator procedure generated by define-struct
,
, or make-struct-type
, make-struct-field-mutator
#f
otherwise.
6 This procedure can be another structure that acts as a procedure. The immutability of procedure fields disallows cycles in the procedure graph, so that the procedure call will eventually continue with a non-structure procedure.