330 lines
13 KiB
Racket
330 lines
13 KiB
Racket
#lang scribble/doc
|
|
|
|
@begin[(require scribble/manual scribble/eval
|
|
scheme/sandbox)
|
|
(require (for-label typed-scheme
|
|
scheme/list srfi/14
|
|
version/check))]
|
|
|
|
@begin[
|
|
(define (item* header . args) (apply item @bold[header]{: } args))
|
|
(define-syntax-rule (tmod forms ...) (schememod typed-scheme forms ...))
|
|
(define (gtech . x) (apply tech x #:doc '(lib "scribblings/guide/guide.scrbl")))
|
|
(define (rtech . x) (apply tech x #:doc '(lib "scribblings/reference/reference.scrbl")))
|
|
]
|
|
|
|
@title[#:tag "top"]{The Typed Scheme Reference}
|
|
|
|
@author["Sam Tobin-Hochstadt"]
|
|
|
|
@(defmodulelang typed-scheme)
|
|
|
|
@section[#:tag "type-ref"]{Type Reference}
|
|
|
|
@subsubsub*section{Base Types}
|
|
@deftogether[(
|
|
@defidform[Number]
|
|
@defidform[Integer]
|
|
@defidform[Boolean]
|
|
@defidform[String]
|
|
@defidform[Keyword]
|
|
@defidform[Symbol]
|
|
@defidform[Void]
|
|
@defidform[Input-Port]
|
|
@defidform[Output-Port]
|
|
@defidform[Path]
|
|
@defidform[Regexp]
|
|
@defidform[PRegexp]
|
|
@defidform[Syntax]
|
|
@defidform[Identifier]
|
|
@defidform[Bytes]
|
|
@defidform[Namespace]
|
|
@defidform[EOF]
|
|
@defidform[Continuation-Mark-Set]
|
|
@defidform[Char])]{
|
|
These types represent primitive Scheme data. Note that @scheme[Integer] represents exact integers.}
|
|
|
|
@defidform[Any]{Any Scheme value. All other types are subtypes of @scheme[Any].}
|
|
|
|
The following base types are parameteric in their type arguments.
|
|
|
|
@defform[(Listof t)]{Homogenous @rtech{lists} of @scheme[t]}
|
|
@defform[(Boxof t)]{A @rtech{box} of @scheme[t]}
|
|
@defform[(Syntaxof t)]{A @rtech{syntax object} containing a @scheme[t]}
|
|
@defform[(Vectorof t)]{Homogenous @rtech{vectors} of @scheme[t]}
|
|
@defform[(Option t)]{Either @scheme[t] of @scheme[#f]}
|
|
@defform*[[(Parameter t)
|
|
(Parameter s t)]]{A @rtech{parameter} of @scheme[t]. If two type arguments are supplied,
|
|
the first is the type the parameter accepts, and the second is the type returned.}
|
|
@defform[(Pair s t)]{is the pair containing @scheme[s] as the @scheme[car]
|
|
and @scheme[t] as the @scheme[cdr]}
|
|
@defform[(HashTable k v)]{is the type of a @rtech{hash table} with key type
|
|
@scheme[k] and value type @scheme[v].}
|
|
|
|
@subsubsub*section{Type Constructors}
|
|
|
|
@defform*[#:id -> #:literals (* ...)
|
|
[(dom ... -> rng)
|
|
(dom ... rest * -> rng)
|
|
(dom ... rest ... bound -> rng)
|
|
(dom -> rng : pred)]]{is the type of functions from the (possibly-empty)
|
|
sequence @scheme[dom ...] to the @scheme[rng] type. The second form
|
|
specifies a uniform rest argument of type @scheme[rest], and the
|
|
third form specifies a non-uniform rest argument of type
|
|
@scheme[rest] with bound @scheme[bound]. In the third form, the
|
|
second occurrence of @scheme[...] is literal, and @scheme[bound]
|
|
must be an identifier denoting a type variable. In the fourth form,
|
|
there must be only one @scheme[dom] and @scheme[pred] is the type
|
|
checked by the predicate.}
|
|
@defform[(U t ...)]{is the union of the types @scheme[t ...]}
|
|
@defform[(case-lambda fun-ty ...)]{is a function that behaves like all of
|
|
the @scheme[fun-ty]s. The @scheme[fun-ty]s must all be function
|
|
types constructed with @scheme[->].}
|
|
@defform/none[(t t1 t2 ...)]{is the instantiation of the parametric type
|
|
@scheme[t] at types @scheme[t1 t2 ...]}
|
|
@defform[(All (v ...) t)]{is a parameterization of type @scheme[t], with
|
|
type variables @scheme[v ...]}
|
|
@defform[(List t ...)]{is the type of the list with one element, in order,
|
|
for each type provided to the @scheme[List] type constructor.}
|
|
@defform[(values t ...)]{is the type of a sequence of multiple values, with
|
|
types @scheme[t ...]. This can only appear as the return type of a
|
|
function.}
|
|
@defform/none[v]{where @scheme[v] is a number, boolean or string, is the singleton type containing only that value}
|
|
@defform/none['val]{where @scheme[val] is a Scheme value, is the singleton type containing only that value}
|
|
@defform/none[i]{where @scheme[i] is an identifier can be a reference to a type
|
|
name or a type variable}
|
|
@defform[(Rec n t)]{is a recursive type where @scheme[n] is bound to the
|
|
recursive type in the body @scheme[t]}
|
|
|
|
Other types cannot be written by the programmer, but are used
|
|
internally and may appear in error messages.
|
|
|
|
@defform/none[(struct:n (t ...))]{is the type of structures named
|
|
@scheme[n] with field types @scheme[t]. There may be multiple such
|
|
types with the same printed representation.}
|
|
@defform/none[<n>]{is the printed representation of a reference to the
|
|
type variable @scheme[n]}
|
|
|
|
@section[#:tag "special-forms"]{Special Form Reference}
|
|
|
|
Typed Scheme provides a variety of special forms above and beyond
|
|
those in PLT Scheme. They are used for annotating variables with types,
|
|
creating new types, and annotating expressions.
|
|
|
|
@subsection{Binding Forms}
|
|
|
|
@scheme[_loop], @scheme[_f], @scheme[_a], and @scheme[_v] are names, @scheme[_t] is a type.
|
|
@scheme[_e] is an expression and @scheme[_body] is a block.
|
|
|
|
@defform*[[
|
|
(let: ([v : t e] ...) . body)
|
|
(let: loop : t0 ([v : t e] ...) . body)]]{
|
|
Local bindings, like @scheme[let], each with
|
|
associated types. In the second form, @scheme[_t0] is the type of the
|
|
result of @scheme[_loop] (and thus the result of the entire
|
|
expression as well as the final
|
|
expression in @scheme[body]).}
|
|
@deftogether[[
|
|
@defform[(letrec: ([v : t e] ...) . body)]
|
|
@defform[(let*: ([v : t e] ...) . body)]]]{Type-annotated versions of
|
|
@scheme[letrec] and @scheme[let*].}
|
|
|
|
@deftogether[[
|
|
@defform[(let/cc: v : t . body)]
|
|
@defform[(let/ec: v : t . body)]]]{Type-annotated versions of
|
|
@scheme[let/cc] and @scheme[let/ec].}
|
|
|
|
@subsection{Anonymous Functions}
|
|
|
|
@defform/subs[(lambda: formals . body)
|
|
([formals ([v : t] ...)
|
|
([v : t] ... . [v : t])])]{
|
|
A function of the formal arguments @scheme[v], where each formal
|
|
argument has the associated type. If a rest argument is present, then
|
|
it has type @scheme[(Listof t)].}
|
|
@defform[(λ: formals . body)]{
|
|
An alias for the same form using @scheme[lambda:].}
|
|
@defform[(plambda: (a ...) formals . body)]{
|
|
A polymorphic function, abstracted over the type variables
|
|
@scheme[a]. The type variables @scheme[a] are bound in both the types
|
|
of the formal, and in any type expressions in the @scheme[body].}
|
|
@defform[(case-lambda: [formals body] ...)]{
|
|
A function of multiple arities. Note that each @scheme[formals] must have a
|
|
different arity.}
|
|
@defform[(pcase-lambda: (a ...) [formals body] ...)]{
|
|
A polymorphic function of multiple arities.}
|
|
|
|
@subsection{Loops}
|
|
|
|
@defform/subs[(do: : u ([id : t init-expr step-expr-maybe] ...)
|
|
(stop?-expr finish-expr ...)
|
|
expr ...+)
|
|
([step-expr-maybe code:blank
|
|
step-expr])]{
|
|
Like @scheme[do], but each @scheme[id] having the associated type @scheme[t], and
|
|
the final body @scheme[expr] having the type @scheme[u].
|
|
}
|
|
|
|
|
|
@subsection{Definitions}
|
|
|
|
@defform*[[(define: v : t e)
|
|
(define: (f . formals) : t . body)
|
|
(define: (a ...) (f . formals) : t . body)]]{
|
|
These forms define variables, with annotated types. The first form
|
|
defines @scheme[v] with type @scheme[t] and value @scheme[e]. The
|
|
second and third forms defines a function @scheme[f] with appropriate
|
|
types. In most cases, use of @scheme[:] is preferred to use of @scheme[define:].}
|
|
|
|
|
|
|
|
@subsection{Structure Definitions}
|
|
@defform/subs[
|
|
(define-struct: maybe-type-vars name-spec ([f : t] ...))
|
|
([maybe-type-vars code:blank (v ...)]
|
|
[name-spec name (name parent)])]{
|
|
Defines a @rtech{structure} with the name @scheme[name], where the
|
|
fields @scheme[f] have types @scheme[t]. When @scheme[parent], the
|
|
structure is a substructure of @scheme[parent]. When
|
|
@scheme[maybe-type-vars] is present, the structure is polymorphic in the type
|
|
variables @scheme[v].}
|
|
|
|
@defform/subs[
|
|
(define-struct/exec: name-spec ([f : t] ...) [e : proc-t])
|
|
([name-spec name (name parent)])]{
|
|
Like @scheme[define-struct:], but defines an procedural structure.
|
|
The procdure @scheme[e] is used as the value for @scheme[prop:procedure], and must have type @scheme[proc-t].}
|
|
|
|
@subsection{Type Aliases}
|
|
@defform*[[(define-type-alias name t)
|
|
(define-type-alias (name v ...) t)]]{
|
|
The first form defines @scheme[name] as type, with the same meaning as
|
|
@scheme[t]. The second form is equivalent to
|
|
@scheme[(define-type-alias name (All (v ...) t))]. Type aliases may
|
|
refer to other type aliases or types defined in the same module, but
|
|
cycles among type aliases are prohibited.}
|
|
|
|
|
|
@subsection{Type Annotation and Instantiation}
|
|
|
|
@defform[(: v t)]{This declares that @scheme[v] has type @scheme[t].
|
|
The definition of @scheme[v] must appear after this declaration. This
|
|
can be used anywhere a definition form may be used.}
|
|
|
|
@defform[(provide: [v t] ...)]{This declares that the @scheme[v]s have
|
|
the types @scheme[t], and also provides all of the @scheme[v]s.}
|
|
|
|
@litchar{#{v : t}} This declares that the variable @scheme[v] has type
|
|
@scheme[t]. This is legal only for binding occurences of @scheme[_v].
|
|
|
|
@defform[(ann e t)]{Ensure that @scheme[e] has type @scheme[t], or
|
|
some subtype. The entire expression has type @scheme[t].
|
|
This is legal only in expression contexts.}
|
|
|
|
@litchar{#{e :: t}} This is identical to @scheme[(ann e t)].
|
|
|
|
@defform[(inst e t ...)]{Instantiate the type of @scheme[e] with types
|
|
@scheme[t ...]. @scheme[e] must have a polymorphic type with the
|
|
appropriate number of type variables. This is legal only in expression
|
|
contexts.}
|
|
|
|
@schemevarfont|{#{e @ t ...}}| This is identical to @scheme[(inst e t ...)].
|
|
|
|
@subsection{Require}
|
|
|
|
Here, @scheme[_m] is a module spec, @scheme[_pred] is an identifier
|
|
naming a predicate, and @scheme[_r] is an optionally-renamed identifier.
|
|
|
|
@defform/subs[#:literals (struct opaque)
|
|
(require/typed m rt-clause ...)
|
|
([rt-clause [r t]
|
|
[struct name ([f : t] ...)]
|
|
[struct (name parent) ([f : t] ...)]
|
|
[opaque t pred]])
|
|
]{This form requires identifiers from the module @scheme[m], giving
|
|
them the specified types.
|
|
|
|
The first form requires @scheme[r], giving it type @scheme[t].
|
|
|
|
@index["struct"]{The second and third forms} require the struct with name @scheme[name]
|
|
with fields @scheme[f ...], where each field has type @scheme[t]. The
|
|
third form allows a @scheme[parent] structure type to be specified.
|
|
The parent type must already be a structure type known to Typed
|
|
Scheme, either built-in or via @scheme[require/typed]. The
|
|
structure predicate has the appropriate Typed Scheme filter type so
|
|
that it may be used as a predicate in @scheme[if] expressions in Typed
|
|
Scheme.
|
|
|
|
@index["opaque"]{The fourth case} defines a new type @scheme[t]. @scheme[pred], imported from
|
|
module @scheme[m], is a predicate for this type. The type is defined
|
|
as precisely those values to which @scheme[pred] produces
|
|
@scheme[#t]. @scheme[pred] must have type @scheme[(Any -> Boolean)].
|
|
Opaque types must be required lexically before they are used.
|
|
|
|
In all cases, the identifiers are protected with @rtech{contracts} which
|
|
enforce the specified types. If this contract fails, the module
|
|
@scheme[m] is blamed.
|
|
|
|
Some types, notably polymorphic types constructed with @scheme[All],
|
|
cannot be converted to contracts and raise a static error when used in
|
|
a @scheme[require/typed] form.}
|
|
|
|
@section{Libraries Provided With Typed Scheme}
|
|
|
|
The @schememodname[typed-scheme] language corresponds to the
|
|
@schememodname[scheme/base] language---that is, any identifier provided
|
|
by @schememodname[scheme/base], such as @scheme[mod] is available by default in
|
|
@schememodname[typed-scheme].
|
|
|
|
@schememod[typed-scheme
|
|
(modulo 12 2)
|
|
]
|
|
|
|
Any value provided by @schememodname[scheme] is available by simply
|
|
@scheme[require]ing it; use of @scheme[require/typed] is not
|
|
neccessary.
|
|
|
|
@schememod[typed-scheme
|
|
(require scheme/list)
|
|
(display (first (list 1 2 3)))
|
|
]
|
|
|
|
Some libraries have counterparts in the @schemeidfont{typed}
|
|
collection, which provide the same exports as the untyped versions.
|
|
Such libraries include @schememodname[srfi/14],
|
|
@schememodname[net/url], and many others.
|
|
|
|
@schememod[typed-scheme
|
|
(require typed/srfi/14)
|
|
(char-set= (string->char-set "hello")
|
|
(string->char-set "olleh"))
|
|
]
|
|
|
|
To participate in making more libraries available, please visit
|
|
@link["http://www.ccs.neu.edu/home/samth/adapt/"]{here}.
|
|
|
|
|
|
Other libraries can be used with Typed Scheme via
|
|
@scheme[require/typed].
|
|
|
|
@schememod[typed-scheme
|
|
(require/typed version/check
|
|
[check-version (-> (U Symbol (Listof Any)))])
|
|
(check-version)
|
|
]
|
|
|
|
@section{Typed Scheme Syntax Without Type Checking}
|
|
|
|
@defmodulelang[typed-scheme/no-check]
|
|
|
|
On occasions where the Typed Scheme syntax is useful, but actual
|
|
typechecking is not desired, the @schememodname[typed-scheme/no-check]
|
|
language is useful. It provides the same bindings and syntax as Typed
|
|
Scheme, but does no type checking.
|
|
|
|
Examples:
|
|
|
|
@schememod[typed-scheme/no-check
|
|
(: x Number)
|
|
(define x "not-a-number")]
|