566 lines
26 KiB
Racket
566 lines
26 KiB
Racket
#lang scribble/doc
|
|
@(require "mz.ss")
|
|
|
|
@(define-syntax op
|
|
(syntax-rules ()
|
|
[(_ (x ...)) (x ...)]
|
|
[(_ id) @scheme[id]]))
|
|
@(define-syntax-rule (operations i ...)
|
|
(itemlist #:style 'compact @item{@op[i]} ...))
|
|
|
|
@title[#:tag "chaperones"]{Impersonators and Chaperones}
|
|
|
|
An @deftech{impersonator} is a wrapper for a value where the wrapper
|
|
redirects certain of the value's operations. Impersonators apply only to procedures,
|
|
@tech{structures} for which an accessor or mutator is available,
|
|
@tech{structure types}, @tech{hash tables}, @tech{vectors},
|
|
and @tech{box}es. An impersonator is @scheme[equal?] to the original
|
|
value, but not @scheme[eq?] to the original value.
|
|
|
|
A @deftech{chaperone} is a kind of impersonator whose refinement of a value's
|
|
operation is restricted to side effects (including, in particular,
|
|
raising an exception) or chaperoning values supplied to or produced by
|
|
the operation. For example, a vector chaperone can redirect
|
|
@scheme[vector-ref] to raise an exception if the accessed vector slot
|
|
contains a string, or it can cause the result of @scheme[vector-ref]
|
|
to be a chaperoned variant of the value that is in the accessed vector
|
|
slot, but it cannot redirect @scheme[vector-ref] to produce a value
|
|
that is arbitrarily different from the value in the vector slot.
|
|
|
|
A non-@tech{chaperone} @tech{impersonator}, in contrast, can refine an operation to swap one
|
|
value for any another. An impersonator cannot be applied to an immutable value
|
|
or refine the access to an immutable field in an instance of a @tech{structure
|
|
type}, since arbitrary replacement of an operation's value amounts to
|
|
mutation of the impersonated value.
|
|
|
|
Beware that each of the following operations can be redirected to
|
|
arbitrary procedure through impersonators on the operation's
|
|
argument---assuming that the operation is available to the creator of
|
|
the impersonator:
|
|
|
|
@operations[@t{a structure-field accesor}
|
|
@t{a structure-field mutator}
|
|
@t{a structure type property accessor}
|
|
@t{application of a procedure}
|
|
unbox set-box!
|
|
vector-ref vector-set!
|
|
hash-ref hash-set hash-set! hash-remove hash-remove!]
|
|
|
|
Derived operations, such as printing a value, can be redirected
|
|
through impersonators due to their use of accessor functions. The
|
|
@scheme[equal?], @scheme[equal-hash-code], and
|
|
@scheme[equal-secondary-hash-code] operations, in contrast, may bypass
|
|
impersonators (but they are not obliged to).
|
|
|
|
In addition to redirecting operations that work on a value, a
|
|
impersonator can include @deftech{impersonator properties} for an impersonated
|
|
value. An @tech{impersonator property} is similar to a @tech{structure
|
|
type property}, but it applies to impersonators instead of structure
|
|
types and their instances.
|
|
|
|
|
|
@defproc[(impersonator? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is an @tech{impersonator}, @scheme[#f] otherwise.
|
|
|
|
Programs and libraries generally should avoid @scheme[impersonator?] and
|
|
treat impersonators the same as non-impersonator values. In rare cases,
|
|
@scheme[impersonator?] may be needed to guard against redirection by an
|
|
impersonator of an operation to an arbitrary procedure.}
|
|
|
|
|
|
@defproc[(chaperone? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a @tech{chaperone}, @scheme[#f] otherwise.
|
|
|
|
Programs and libraries generally should avoid @scheme[chaperone?] for
|
|
the same reason that they should avoid @racket[impersonator?].}
|
|
|
|
|
|
@defproc[(impersonator-of? [v1 any/c] [v2 any/c]) boolean?]{
|
|
|
|
Indicates whether @scheme[v1] can be considered equivalent modulo
|
|
impersonators to @scheme[v2].
|
|
|
|
For values that include no impersonators, @scheme[v1] and @scheme[v2] can
|
|
be considered impersonators of each other if they are @scheme[equal?].
|
|
|
|
Otherwise, all impersonators of @scheme[v2] must be intact in @scheme[v1],
|
|
in the sense that parts of @scheme[v2] must be derived from
|
|
@scheme[v1] through one of the impersonator constructors (e.g.,
|
|
@scheme[impersonate-procedure] or @racket[chaperone-procedure]).
|
|
|
|
See also @racket[prop:impersonator-of].}
|
|
|
|
|
|
@defproc[(chaperone-of? [v1 any/c] [v2 any/c]) boolean?]{
|
|
|
|
Indicates whether @scheme[v1] can be considered equivalent modulo
|
|
chaperones to @scheme[v2].
|
|
|
|
For values that include no chaperones, @scheme[v1] and @scheme[v2] can
|
|
be considered chaperones of each other if they are @scheme[equal?],
|
|
except that the mutability of vectors and boxes with @scheme[v1] and
|
|
@scheme[v2] must be the same.
|
|
|
|
Otherwise, all chaperones of @scheme[v2] must be intact in
|
|
@scheme[v1], in the sense that parts of @scheme[v2] must be derived
|
|
from @scheme[v1] through one of the chaperone constructors (e.g.,
|
|
@scheme[chaperone-procedure]).}
|
|
|
|
@; ------------------------------------------------------------
|
|
@section{Impersonator Constructors}
|
|
|
|
@defproc[(impersonate-procedure [proc procedure?]
|
|
[wrapper-proc procedure?]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c procedure? impersonator?)]{
|
|
|
|
Returns an impersonator procedure that has the same arity, name, and
|
|
other attributes as @scheme[proc]. When the impersonator procedure is
|
|
applied, the arguments are first passed to @scheme[wrapper-proc], and
|
|
then the results from @scheme[wrapper-proc] are passed to
|
|
@scheme[proc]. The @scheme[wrapper-proc] can also supply a procedure
|
|
that processes the results of @scheme[proc].
|
|
|
|
The arity of @scheme[wrapper-proc] must include the arity of
|
|
@scheme[proc]. The allowed keyword arguments of @scheme[wrapper-proc]
|
|
must be a superset of the allowed keywords of @scheme[proc]. The
|
|
required keyword arguments of @scheme[wrapper-proc] must be a subset
|
|
of the required keywords of @scheme[proc].
|
|
|
|
For applications without keywords, the result of @scheme[wrapper-proc]
|
|
must be either the same number of values as supplied to it or one more
|
|
than the number of supplied values, where an extra result is supplied
|
|
before the others. The additional result, if any, must be a procedure
|
|
that accepts as many results as produced by @scheme[proc]; it must
|
|
return the same number of results. If @scheme[wrapper-proc] returns
|
|
the same number of values as it is given (i.e., it does not return a
|
|
procedure to impersonator @scheme[proc]'s result), then @scheme[proc] is
|
|
called in @tech{tail position} with respect to the call to the impersonator.
|
|
|
|
For applications that include keyword arguments, @scheme[wrapper-proc]
|
|
must return an additional value before any other values but after the
|
|
result-impersonating procedure (if any). The additional value must be a
|
|
list of replacements for the keyword arguments that were supplied to the
|
|
impersonator (i.e., not counting optional arguments that were
|
|
not supplied). The arguments must be ordered according to the sorted
|
|
order of the supplied arguments' keywords.
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[procedure-impersonator] must be even) add impersonator properties
|
|
or override impersonator-property values of @scheme[proc].
|
|
|
|
If any @scheme[prop] is @racket[impersonator-prop:application-mark] and if the
|
|
associated @racket[prop-val] is a pair, then the call to @racket[proc]
|
|
is wrapped with @racket[with-continuation-mark] using @racket[(car
|
|
prop-val)] as the mark key and @racket[(cdr prop-val)] as the mark
|
|
value. In addition, if @racket[continuation-mark-set-first] with
|
|
@racket[(car prop-val)] produces a value for the immediate
|
|
continuation frame of the call to the impersonated procedure, the value is
|
|
also installed as an immediate value for @racket[(car prop-val)] as a
|
|
mark during the call to @racket[wrapper-proc] (which allows tail-calls
|
|
of impersonators with respect to wrapping impersonators to be detected within
|
|
@racket[wrapper-proc]).}
|
|
|
|
|
|
@defproc[(impersonate-struct [v any/c]
|
|
[orig-proc (or/c struct-accessor-procedure?
|
|
struct-mutator-procedure?
|
|
struct-type-property-accessor-procedure?)]
|
|
[redirect-proc procedure?] ... ...
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
any/c]{
|
|
|
|
Returns an impersonator of @scheme[v], with redirect certain
|
|
operations on the impersonated value. The @scheme[orig-proc]s
|
|
indicate the operations to redirect, and the corresponding
|
|
@scheme[redirect-proc]s supply the redirections.
|
|
|
|
The protocol for a @scheme[redirect-proc] depends on the corresponding
|
|
@scheme[orig-proc]:
|
|
|
|
@itemlist[
|
|
|
|
@item{A structure-field accessor: @scheme[redirect-proc]
|
|
must accept two arguments, @scheme[v] and the value
|
|
@scheme[_field-v] that @scheme[orig-proc] produces for
|
|
@scheme[v]; it must return a replacement for
|
|
@scheme[_field-v]. The corresponding field must not be
|
|
immutable.}
|
|
|
|
@item{A structure-field mutator: @scheme[redirect-proc] must accept
|
|
two arguments, @scheme[v] and the value @scheme[_field-v]
|
|
supplied to the mutator; it must return a replacement for
|
|
@scheme[_field-v] to be propagated to @scheme[orig-proc] and
|
|
@scheme[v].}
|
|
|
|
@item{A property accessor: @racket[redirect-proc] uses the same
|
|
protocol as for a structure-field accessor. The accessor's
|
|
property must have been created with @racket['can-impersonate]
|
|
as the second argument to @racket[make-struct-type-property].}
|
|
|
|
]
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[impersonate-struct] must be odd) add impersonator properties
|
|
or override impersonator-property values of @scheme[v].}
|
|
|
|
@defproc[(impersonate-vector [vec (and/c vector? (not/c immutable?))]
|
|
[ref-proc (vector? exact-nonnegative-integer? any/c . -> . any/c)]
|
|
[set-proc (vector? exact-nonnegative-integer? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c vector? impersonator?)]{
|
|
|
|
Returns an impersonator of @scheme[vec], which redirects the
|
|
@scheme[vector-ref] and @scheme[vector-set!] operations.
|
|
|
|
The @scheme[ref-proc] must accept @scheme[vec], an index passed to
|
|
@scheme[vector-ref], and the value that @scheme[vector-ref] on
|
|
@scheme[vec] produces for the given index; it must produce a
|
|
replacement for the value, which is the result of @scheme[vector-ref]
|
|
on the impersonator.
|
|
|
|
The @scheme[set-proc] must accept @scheme[vec], an index passed to
|
|
@scheme[vector-set!], and the value passed to @scheme[vector-set!]; it
|
|
must produce a replacement for the value, which is used
|
|
with @scheme[vector-set!] on the original @scheme[vec] to install the
|
|
value.
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[impersonate-vector] must be odd) add impersonator properties
|
|
or override impersonator-property values of @scheme[vec].}
|
|
|
|
@defproc[(impersonate-box [box (and/c box? (not/c immutable?))]
|
|
[unbox-proc (box? any/c . -> . any/c)]
|
|
[set-proc (box? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c box? impersonator?)]{
|
|
|
|
Returns an impersonator of @scheme[bx], which redirects the
|
|
@scheme[unbox] and @scheme[set-box!] operations.
|
|
|
|
The @scheme[unbox-proc] must accept @scheme[bx] and the value that
|
|
@scheme[unbox] on @scheme[bx] produces index; it must produce a replacement
|
|
value, which is the result of
|
|
@scheme[unbox] on the impersonator.
|
|
|
|
The @scheme[set-proc] must accept @scheme[bx] and the value passed to
|
|
@scheme[set-box!]; it must produce a replacement
|
|
value, which is used with @scheme[set-box!] on the original
|
|
@scheme[bx] to install the value.
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[impersonate-box] must be odd) add impersonator properties
|
|
or override impersonator-property values of @scheme[bx].}
|
|
|
|
|
|
@defproc[(impersonate-hash [hash (and/c hash? (not/c immutable?))]
|
|
[ref-proc (hash? any/c . -> . (values
|
|
any/c
|
|
(hash? any/c any/c . -> . any/c)))]
|
|
[set-proc (hash? any/c any/c . -> . (values any/c any/c))]
|
|
[remove-proc (hash? any/c . -> . any/c)]
|
|
[key-proc (hash? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c hash? impersonator?)]{
|
|
|
|
Returns an impersonator of @scheme[hash], which redirects the
|
|
@scheme[hash-ref], @scheme[hash-set!] or @scheme[hash-set] (as
|
|
applicable), and @scheme[hash-remove] or @scheme[hash-remove!] (as
|
|
application) operations. When
|
|
@scheme[hash-set] or @scheme[hash-remove] is used on an impersonator of a hash
|
|
table, the result is an impersonator with the same redirecting procedures.
|
|
In addition, operations like
|
|
@scheme[hash-iterate-key] or @scheme[hash-map], which extract
|
|
keys from the table, use @scheme[key-proc] to filter keys extracted
|
|
from the table. Operations like @scheme[hash-iterate-value] or
|
|
@scheme[hash-iterate-map] implicitly use @scheme[hash-ref] and
|
|
therefore redirect through @scheme[ref-proc].
|
|
|
|
The @scheme[ref-proc] must accept @scheme[hash] and a key passed
|
|
@scheme[hash-ref]. It must return a replacement key
|
|
as well as a procedure. The returned procedure is called only if the
|
|
returned key is found in @scheme[hash] via @scheme[hash-ref], in which
|
|
case the procedure is called with @scheme[hash], the previously
|
|
returned key, and the found value. The returned procedure must itself
|
|
return a replacement for the found value.
|
|
|
|
The @scheme[set-proc] must accept @scheme[hash], a key passed to
|
|
@scheme[hash-set!] or @scheme[hash-set], and the value passed to
|
|
@scheme[hash-set!] or @scheme[hash-set]; it must produce two values: a
|
|
replacement for the key and a replacement for the value. The returned
|
|
key and value are used with @scheme[hash-set!] or @scheme[hash-set] on
|
|
the original @scheme[hash] to install the value.
|
|
|
|
The @scheme[remove-proc] must accept @scheme[hash] and a key passed to
|
|
@scheme[hash-remove!] or @scheme[hash-remove]; it must produce the a
|
|
replacement for the key, which is used with @scheme[hash-remove!] or
|
|
@scheme[hash-remove] on the original @scheme[hash] to remove any
|
|
mapping using the (impersonator-replaced) key.
|
|
|
|
The @scheme[key-proc] must accept @scheme[hash] and a key that has
|
|
been extracted from @scheme[hash] (by @scheme[hash-iterate-key] or
|
|
other operations that use @scheme[hash-iterate-key] internally); it
|
|
must produce a replacement for the key, which is then reported as a
|
|
key extracted from the table.
|
|
|
|
The @racket[hash-iterate-value], @racket[hash-map], or
|
|
@racket[hash-for-each] functions use a combination of
|
|
@racket[hash-iterate-key] and @racket[hash-ref]. If a key
|
|
produced by @scheme[key-proc] does not yield a value through
|
|
@racket[hash-ref], then the @exnraise[exn:fail:contract].
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[impersonate-hash] must be odd) add impersonator properties
|
|
or override impersonator-property values of @scheme[hash].}
|
|
|
|
|
|
@defthing[prop:impersonator-of struct-type-property?]{
|
|
|
|
A @tech{structure type property} (see @secref["structprops"]) that
|
|
supplies a procedure for extracting an impersonated value from a structure
|
|
that represents an impersonator. The property is used for @racket[impersonator-of?]
|
|
as well as @racket[equal?].
|
|
|
|
The property value must be a procedure of one argument, which is a
|
|
structure whose structure type has the property. The result can be
|
|
@scheme[#f] to indicate the structure does not represent an impersonator,
|
|
otherwise the result is a value for which the original structure is an
|
|
impersonator (so the original structure is an @racket[impersonator-of?] and
|
|
@racket[equal?] to the result value). The result value must have the
|
|
same @racket[prop:impersonator-of] and @racket[prop:equal+hash] property
|
|
values as the original structure, and the property values must be
|
|
inherited from the same structure type (which ensures some consistency
|
|
between @racket[impersonator-of?] and @racket[equal?]).}
|
|
|
|
@; ------------------------------------------------------------
|
|
@section{Chaperone Constructors}
|
|
|
|
@defproc[(chaperone-procedure [proc procedure?]
|
|
[wrapper-proc procedure?]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c procedure? chaperone?)]{
|
|
|
|
Like @racket[impersonate-procedure], but for each value supplied to
|
|
@scheme[wrapper-proc], the corresponding result must be the same or a
|
|
chaperone of (in the sense of @scheme[chaperone-of?]) the supplied
|
|
value. The additional result, if any, that precedes the chaperoned
|
|
values must be a procedure that accepts as many results as produced by
|
|
@scheme[proc]; it must return the same number of results, each of
|
|
which is the same or a chaperone of the corresponding original result.
|
|
|
|
For applications that include keyword arguments, @scheme[wrapper-proc]
|
|
must return an additional value before any other values but after the
|
|
result-chaperoning procedure (if any). The additional value must be a
|
|
list of chaperones of the keyword arguments that were supplied to the
|
|
chaperone procedure (i.e., not counting optional arguments that were
|
|
not supplied). The arguments must be ordered according to the sorted
|
|
order of the supplied arguments' keywords.}
|
|
|
|
@defproc[(chaperone-struct [v any/c]
|
|
[orig-proc (or/c struct-accessor-procedure?
|
|
struct-mutator-procedure?
|
|
struct-type-property-accessor-procedure?
|
|
(one-of/c struct-info))]
|
|
[redirect-proc procedure?] ... ...
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
any/c]{
|
|
|
|
Like @racket[impersonate-struct], but with the following refinements:
|
|
|
|
@itemlist[
|
|
|
|
@item{With a structure-field accessor as @racket[orig-proc],
|
|
@scheme[redirect-proc] must accept two arguments, @scheme[v] and
|
|
the value @scheme[_field-v] that @scheme[orig-proc] produces for
|
|
@scheme[v]; it must return a chaperone of @scheme[_field-v]. The
|
|
corresponding field may be immutable.}
|
|
|
|
@item{With structure-field mutator as @racket[orig-proc],
|
|
@scheme[redirect-proc] must accept two arguments, @scheme[v] and
|
|
the value @scheme[_field-v] supplied to the mutator; it must
|
|
return a chaperone of @scheme[_field-v] to be propagated to
|
|
@scheme[orig-proc] and @scheme[v].}
|
|
|
|
@item{A property accessor can be supplied as @racket[orig-proc], and
|
|
the property need not have been created with
|
|
@racket['can-impersonate]. The corresponding
|
|
@racket[redirect-proc] uses the same protocol as for a
|
|
structure-field accessor.}
|
|
|
|
@item{With @scheme[struct-info] as @racket[orig-proc], the
|
|
corresponding @scheme[redirect-proc] must accept two values,
|
|
which are the results of @scheme[struct-info] on @scheme[v]; it
|
|
must return each values or a chaperone of each value. The
|
|
@scheme[redirect-proc] is not called if @scheme[struct-info] would
|
|
return @scheme[#f] as its first argument.}
|
|
|
|
]
|
|
|
|
An @scheme[orig-proc] can be @scheme[struct-info] only if some other
|
|
@scheme[orig-proc] is supplied, and each @scheme[orig-proc] must
|
|
indicate a distinct operation. If no @scheme[orig-proc]s are supplied,
|
|
then no @scheme[prop]s must be supplied, and @scheme[v] is returned
|
|
unchaperoned.}
|
|
|
|
@defproc[(chaperone-vector [vec vector?]
|
|
[ref-proc (vector? exact-nonnegative-integer? any/c . -> . any/c)]
|
|
[set-proc (vector? exact-nonnegative-integer? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c vector? chaperone?)]{
|
|
|
|
Like @racket[impersonate-vector], but with support for immutable vectors. The
|
|
@scheme[ref-proc] procedure must produce the same value or a chaperone
|
|
of the original value, and @scheme[set-proc] must produce the value
|
|
that is given or a chaperone of the value. The @scheme[set-proc] will
|
|
not be used if @scheme[vec] is immutable.}
|
|
|
|
@defproc[(chaperone-box [bx box?]
|
|
[unbox-proc (box? any/c . -> . any/c)]
|
|
[set-proc (box? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c box? chaperone?)]{
|
|
|
|
Like @racket[prox-box], but with support for immutable boxes. The
|
|
@scheme[unbox-proc] procedure must produce the same value or a
|
|
chaperone of the original value, and @scheme[set-proc] must produce
|
|
the same value or a chaperone of the value that it is given. The
|
|
@scheme[set-proc] will not be used if @scheme[bx] is immutable.}
|
|
|
|
|
|
@defproc[(chaperone-hash [hash hash?]
|
|
[ref-proc (hash? any/c . -> . (values
|
|
any/c
|
|
(hash? any/c any/c . -> . any/c)))]
|
|
[set-proc (hash? any/c any/c . -> . (values any/c any/c))]
|
|
[remove-proc (hash? any/c . -> . any/c)]
|
|
[key-proc (hash? any/c . -> . any/c)]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c hash? chaperone?)]{
|
|
|
|
Like @racket[impersonate-hash], but with constraints on the given functions
|
|
and support for immutable hashes. The @scheme[ref-proc] procedure must
|
|
return a found value or a chaperone of the value. The
|
|
@scheme[set-proc] procedure must produce two values: the key that it
|
|
is given or a chaperone of the key and the value that it is given or a
|
|
chaperone of the value. The @scheme[remove-proc] and @scheme[key-proc]
|
|
procedures must produce the given key or a chaperone of the key.}
|
|
|
|
@defproc[(chaperone-struct-type [struct-type struct-type?]
|
|
[struct-info-proc procedure?]
|
|
[make-constructor-proc (procedure? . -> . procedure?)]
|
|
[guard-proc procedure?]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c struct-type? chaperone?)]{
|
|
|
|
Returns a chaperoned value like @scheme[struct-type], but with
|
|
@scheme[struct-type-info] and @scheme[struct-type-make-constructor]
|
|
operations on the chaperoned structure type redirected. In addition,
|
|
when a new structure type is created as a subtype of the chaperoned
|
|
structure type, @scheme[guard-proc] is interposed as an extra guard on
|
|
creation of instances of the subtype.
|
|
|
|
The @scheme[struct-info-proc] must accept 8 arguments---the result of
|
|
@scheme[struct-type-info] on @scheme[struct-type]. It must return 8
|
|
values, where each is the same or a chaperone of the corresponding
|
|
argument. The 8 values are used as the results of
|
|
@scheme[struct-type-info] for the chaperoned structure type.
|
|
|
|
The @scheme[make-constructor-proc] must accept a single procedure
|
|
argument, which is a constructor produced by
|
|
@scheme[struct-type-make-constructor] on @scheme[struct-type]. It must
|
|
return the same or a chaperone of the procedure, which is used as the
|
|
result of @scheme[struct-type-make-constructor] on the chaperoned
|
|
structure type.
|
|
|
|
The @scheme[guard-proc] must accept as many argument as a constructor
|
|
for @scheme[struct-type]; it must return the same number of arguments,
|
|
each the same or a chaperone of the corresponding argument. The
|
|
@scheme[guard-proc] is added as a constructor guard when a subtype is
|
|
created of the chaperoned structure type.
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[chaperone-struct-type] must be even) add impersonator properties
|
|
or override impersonator-property values of @scheme[struct-type].}
|
|
|
|
@defproc[(chaperone-evt [evt evt?]
|
|
[proc (evt? . -> . (values evt? (any/c . -> . any/c)))]
|
|
[prop impersonator-property?]
|
|
[prop-val any] ... ...)
|
|
(and/c evt? chaperone?)]{
|
|
|
|
Returns a chaperoned value like @scheme[evt], but with @scheme[proc]
|
|
as an event generator when the result is synchronized with functions
|
|
like @racket[sync].
|
|
|
|
The @racket[proc] generator is called on synchronization, much like
|
|
the procedure passed to @racket[guard-evt], except that @racket[proc]
|
|
is given @scheme[evt]. The @racket[proc] must return two values: a
|
|
@tech{synchronizable event} that is a chaperone of @racket[evt], and a
|
|
procedure that is used to check the event's result if it is chosen in
|
|
a selection. The latter procedure accepts the result of @racket[evt],
|
|
and it must return a chaperone of that value.
|
|
|
|
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
|
|
to @scheme[chaperone-evt] must be even) add impersonator properties
|
|
or override impersonator-property values of @scheme[evt].}
|
|
|
|
@; ------------------------------------------------------------
|
|
@section{Impersonator Properties}
|
|
|
|
@defproc[(make-impersonator-property [name symbol?])
|
|
(values impersonator-property?
|
|
(-> any/c boolean?)
|
|
(-> impersonator? any))]{
|
|
|
|
Creates a new @tech{impersonator property} and returns three values:
|
|
|
|
@itemize[
|
|
|
|
@item{an @deftech{impersonator property descriptor}, for use with
|
|
@scheme[impersonate-procedure], @scheme[chaperone-procedure],
|
|
and other impersonator constructors;}
|
|
|
|
@item{an @deftech{impersonator property predicate} procedure, which takes
|
|
an arbitrary value and returns @scheme[#t] if the value is an
|
|
impersonator with a value for the property, @scheme[#f]
|
|
otherwise;}
|
|
|
|
@item{an @deftech{impersonator property accessor} procedure, which
|
|
returns the value associated with an impersonator for the property;
|
|
if a value given to the accessor is not an impersonator or does not
|
|
have a value for the property (i.e. if the corresponding impersonator
|
|
property predicate returns @racket[#f]), the accessor raises
|
|
@exnraise[exn:fail:contract].}
|
|
|
|
]}
|
|
|
|
@defproc[(impersonator-property? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a @tech{impersonator property
|
|
descriptor} value, @scheme[#f] otherwise.}
|
|
|
|
@defproc[(impersonator-property-accessor-procedure? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is an accessor procedure produced
|
|
by @scheme[make-impersonator-property], @scheme[#f] otherwise.}
|
|
|
|
|
|
@defthing[impersonator-prop:application-mark impersonator-property?]{
|
|
|
|
An @tech{impersonator property} that is recognized by @racket[impersonate-procedure]
|
|
and @racket[chaperone-procedure].}
|
|
|