129 lines
4.7 KiB
Racket
129 lines
4.7 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label typed/racket/base
|
|
"adt.lp2.rkt")
|
|
"../lib/doc.rkt")
|
|
@doc-lib-setup
|
|
|
|
@defform[#:kind "type expander"
|
|
#:literals (:)
|
|
(tagged tag field-desc)
|
|
#:grammar
|
|
[(tag Identifier)
|
|
(field-desc field
|
|
[field]
|
|
[field : type])
|
|
(field Identifier)
|
|
(type Type)]]{
|
|
Expands to the type for a tagged structure with the given
|
|
type and fields. If the types for the fields are not given,
|
|
a polymorphic structure is returned.
|
|
|
|
For now, either all types must be given or none, as
|
|
keeping track of which fields are polymorphic and which are
|
|
not would be difficult for the user. In the rare cases
|
|
whrere partially polymorphic fields would be needed, the
|
|
type can easily be described using:
|
|
|
|
@racketblock[
|
|
(define-type (partially-polymorphic A C)
|
|
(tagged some-tag [a A] [b String] [c C] [d Integer]))]}
|
|
|
|
@defform[#:kind "match expander"
|
|
(tagged)]{
|
|
}
|
|
|
|
@defform*[#:literals (:)
|
|
((tagged maybe-instance tag just-field …)
|
|
(tagged maybe-make-instance tag field+value …))
|
|
#:grammar
|
|
[(maybe-instance (code:line)
|
|
#:instance)
|
|
(maybe-make-instance (code:line)
|
|
#:make-instance)
|
|
(tag Identifier)
|
|
(just-field field
|
|
[field]
|
|
[field : type])
|
|
(field+value [field value]
|
|
[field : type value])
|
|
(field Identifier)
|
|
(type Type)
|
|
(value Expression)]]{
|
|
When using the @racket[just-field] syntax, this form
|
|
produces a function which can be used to build an instance
|
|
of the tagged structure, by passing as many values as there
|
|
are fields.
|
|
|
|
When using the @racket[field+value] syntax, this form
|
|
directly returns an instance of the tagged structure, with
|
|
the given values.
|
|
|
|
It is mandatory to disambiguate with either
|
|
@racket[#:instance] or @racket[#:make-instance] when using
|
|
@racket[tagged] with an empty list of fields (i.e. a
|
|
structure with no fields) as it cannot be guessed from the
|
|
syntax otherwise, so it is best to always include it when
|
|
producing a call to @racket[tagged] in a macro.}
|
|
|
|
@defform[(tagged? tag field …)
|
|
#:contracts ([tag Identifier]
|
|
[field Identifier])]{
|
|
Returns a predicate for tagged structures with the given
|
|
@racket[tag] and @racket[field]s.}
|
|
|
|
@defform[(tagged? tag
|
|
#:with-struct with-struct
|
|
field)
|
|
#:contracts ([with-struct struct-type?])]{
|
|
The @racket[#:with-struct] option is reserved for internal
|
|
use. It is used by @racket[#:private] and
|
|
@racket[#:uninterned] in @racket[define-contructor] and
|
|
@racket[define-tagged].}
|
|
|
|
@defidform[#:kind "type"
|
|
TaggedTop]{
|
|
The supertype of all tagged structures.}
|
|
|
|
@defproc[(TaggedTop?) Boolean]{
|
|
Predicate for tagged structures. It will also return
|
|
@racket[#t] for constructors which only value is a promise
|
|
@note{The reason why we wrap the structure with a promise
|
|
is to allow building circular data structures, like what
|
|
is done in the @racket[graph] library. The structure is
|
|
always wrapped in a promise even for non-cyclic data
|
|
structures, so that the @racket[get] operation always
|
|
operates on the same type. Although this incurs an extra
|
|
cost in terms of memory usage, it avoids combinatorial
|
|
blowup of the size of the type of an object which has the
|
|
nested fields @racket[.f₁.f₂.f₃.….fₙ], which would
|
|
otherwise have size @${2ⁿ}, due to the presence of a
|
|
@racket[(U (Promise …) …)] at each level.} for a
|
|
structure, because this is how tagged structures are
|
|
implemented behind the scenes.}
|
|
|
|
@defform[(define-constructor name maybe-private-uninterned maybe-? type …)
|
|
#:grammar
|
|
[(maybe-private-uninterned (code:line)
|
|
#:private
|
|
#:uninterned)
|
|
(maybe-? (code:line)
|
|
(code:line #:? name?))
|
|
(name Identifier)
|
|
(name? Identifier)
|
|
(type Type)]]{
|
|
Binds @racket[name] to the constructor's type-expander,
|
|
match-expander and creation function. @racket[name?] is
|
|
bound to the predicate for that constructor.
|
|
|
|
Unless specified, @racket[name?] is derived from
|
|
@racket[name] by appending @racket[?] to the identifier.
|
|
|
|
@racket[#:private] and @racket[#:uninterned] allow
|
|
specifying a constructor which is not visible from other
|
|
files or declarations. @racket[#:uninterned] constructors
|
|
are subtypes of the default, interened ones, while
|
|
@racket[#:private] are directly subtypes of ConstructorTop,
|
|
meaning that they won't be matched by a "public"
|
|
constructor with the same name.}
|