2 Special Form Reference
Typed Racket provides a variety of special forms above and beyond those in Racket. They are used for annotating variables with types, creating new types, and annotating expressions.
2.1 Binding Forms
loop, f, a, and var are names, type is a type. e is an expression and body is a block.
syntax
(let maybe-tvars (binding ...) . body)
(let loop maybe-ret (binding ...) . body)
binding = [var e] | [var : type e] maybe-tvars =
| #:forall (tvar ...) | #:∀ (tvar ...) maybe-ret =
| : type0
Examples: | |||||||||||||||||
|
Examples: | |||||||||||||||||
|
If polymorphic type variables are provided, they are bound in the type expressions for variable bindings.
Example: | |||
|
syntax
(letrec (binding ...) . body)
syntax
(let* (binding ...) . body)
syntax
(let-values ([(var+type ...) e] ...) . body)
syntax
(letrec-values ([(var+type ...) e] ...) . body)
syntax
(let*-values ([(var+type ...) e] ...) . body)
2.2 Anonymous Functions
syntax
(lambda maybe-tvars formals maybe-ret . body)
formals = (formal ...) | (formal ... . rst) formal = var | [var default-expr] | [var : type] | [var : type default-expr] | keyword var | keyword [var : type] | keyword [var : type default-expr] rst = var | [var : type *] | [var : type ooo bound] maybe-tvars =
| #:forall (tvar ...) | #:∀ (tvar ...) | #:forall (tvar ... ooo) | #:∀ (tvar ... ooo) maybe-ret =
| : type
Examples: | |||||||||
|
Type annotations may also be specified for keyword and optional arguments:
Examples: | ||||||||||||
|
The lambda expression may also specify polymorphic type variables that are bound for the type expressions in the formals.
Examples: | ||||||
|
In addition, a type may optionally be specified for the rest argument with either a uniform type or using a polymorphic type. In the former case, the rest argument is given the type (Listof type) where type is the provided type annotation.
Examples: | |||||||||
|
syntax
(λ formals . body)
syntax
(case-lambda maybe-tvars [formals body] ...)
Polymorphic type variables, if provided, are bound in the type expressions in the formals.
Note that each formals must have a different arity.
Example: | ||||||||||
|
To see how to declare a type for add-map, see the case-> type constructor.
2.3 Loops
syntax
(for type-ann-maybe (for:-clause ...) expr ...+)
type-ann-maybe =
| : u for-clause = [id : t seq-expr] | [(binding ...) seq-expr] | [id seq-expr] | #:when guard binding = id | [id : t]
syntax
(for/list type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/hash type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/hasheq type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/hasheqv type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/vector type-ann-maybe (for-clause ...) expr ...+)
syntax
syntax
(for/and type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/or type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/first type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/last type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/sum type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/product type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/list type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/hash type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/hasheq type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/hasheqv type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/vector type-ann-maybe (for-clause ...) expr ...+)
syntax
syntax
(for*/and type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/or type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/first type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/last type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/sum type-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/product type-ann-maybe (for-clause ...) expr ...+)
syntax
(for/lists type-ann-maybe ([id : t] ...) (for-clause ...) expr ...+)
syntax
(for/fold type-ann-maybe ([id : t init-expr] ...) (for-clause ...) expr ...+)
syntax
(for* void-ann-maybe (for-clause ...) expr ...+)
syntax
(for*/lists type-ann-maybe ([id : t] ...) (for-clause ...) expr ...+)
syntax
(for*/fold type-ann-maybe ([id : t init-expr] ...) (for-clause ...) expr ...+)
syntax
(do : u ([id : t init-expr step-expr-maybe] ...) (stop?-expr finish-expr ...) expr ...+)
step-expr-maybe =
| step-expr
2.4 Definitions
syntax
(define maybe-tvars v maybe-ann e)
(define maybe-tvars header maybe-ann . body)
header = (function-name . formals) | (header . formals) formals = (formal ...) | (formal ... . rst) formal = var | [var default-expr] | [var : type] | [var : type default-expr] | keyword var | keyword [var : type] | keyword [var : type default-expr] rst = var | [var : type *] | [var : type ooo bound] maybe-tvars =
| #:forall (tvar ...) | #:∀ (tvar ...) | #:forall (tvar ... ooo) | #:∀ (tvar ... ooo) maybe-ann =
| : type
The first form defines a variable v to the result of evaluating the expression e. The variable may have an optional type annotation.
Examples: | ||||||
|
If polymorphic type variables are provided, then they are bound for use in the type annotation.
Example: | |||
|
The second form allows the definition of functions with optional type annotations on any variables. If a return type annotation is provided, it is used to check the result of the function.
Like lambda, optional and keyword arguments are supported.
Examples: | ||||||||||||||
|
The function definition form also allows curried function arguments with corresponding type annotations.
Examples: | |||||||||
|
Note that unlike define from racket/base, define does not bind functions with keyword arguments to static information about those functions.
2.5 Structure Definitions
syntax
(struct maybe-type-vars name-spec ([f : t] ...) options ...)
maybe-type-vars =
| (v ...) name-spec = name | name parent options = #:transparent | #:mutable
Options provided have the same meaning as for the struct form from racket/base.
syntax
(define-struct maybe-type-vars name-spec ([f : t] ...) options ...)
maybe-type-vars =
| (v ...) name-spec = name | (name parent) options = #:transparent | #:mutable
syntax
(define-struct/exec name-spec ([f : t] ...) [e : proc-t])
name-spec = name | (name parent)
2.6 Names for Types
syntax
(define-type name t maybe-omit-def)
(define-type (name v ...) t maybe-omit-def)
maybe-omit-def = #:omit-define-syntaxes |
Examples: | ||||||
|
If #:omit-define-syntaxes is specified, no definition of name is created. In this case, some other definition of name is necessary.
If the body of the type definition refers to itself, then the type definition is recursive. Recursion may also occur mutually, if a type refers to a chain of other types that eventually refers back to itself.
Examples: | ||||||||||||
|
However, the recursive reference may not occur immediately inside the type:
Examples: | ||||||||||
|
2.7 Generating Predicates Automatically
syntax
(make-predicate t)
syntax
(define-predicate name t)
2.8 Type Annotation and Instantiation
The second form allows type annotations to elide one level of parentheses for function types.
Examples: | ||||||
|
syntax
(provide: [v t] ...)
syntax
#{v : t}
syntax
(ann e t)
syntax
#{e :: t}
syntax
(cast e t)
Examples: | |||||||||||||||
|
Examples: | ||||||||||||||||||||||
|
syntax
#{e @ t ...}
syntax
#{e @ t ... t ooo bound}
2.9 Require
Here, m is a module spec, pred is an identifier naming a predicate, and maybe-renamed is an optionally-renamed identifier.
syntax
(require/typed m rt-clause ...)
rt-clause = [maybe-renamed t] |
[#:struct name ([f : t] ...) struct-option ...] |
[#:struct (name parent) ([f : t] ...) struct-option ...] | [#:opaque t pred] maybe-renamed = id | (orig-id new-id) struct-option = #:constructor-name constructor-id | #:extra-constructor-name constructor-id
The first case requires maybe-renamed, giving it type t.
The second and third cases require the struct with name name with fields f ..., where each field has type t. The third case allows a parent structure type to be specified. The parent type must already be a structure type known to Typed Racket, either built-in or via require/typed. The structure predicate has the appropriate Typed Racket filter type so that it may be used as a predicate in if expressions in Typed Racket.
Examples: | ||||||||||||||||||||
|
The fourth case defines a new type t. pred, imported from module m, is a predicate for this type. The type is defined as precisely those values to which pred produces #t. pred must have type (Any -> Boolean). Opaque types must be required lexically before they are used.
Examples: | ||||||||||||||||
|
In all cases, the identifiers are protected with contracts which enforce the specified types. If this contract fails, the module m is blamed.
Some types, notably the types of predicates such as number?, cannot be converted to contracts and raise a static error when used in a require/typed form. Here is an example of using case-> in require/typed.
(require/typed racket/base [file-or-directory-modify-seconds (case-> [String -> Exact-Nonnegative-Integer] [String (Option Exact-Nonnegative-Integer) -> (U Exact-Nonnegative-Integer Void)] [String (Option Exact-Nonnegative-Integer) (-> Any) -> Any])])
file-or-directory-modify-seconds has some arguments which are optional, so we need to use case->.
syntax
(require/typed/provide m rt-clause ...)
Examples: | ||||||||||||||
|
2.10 Other Forms
syntax
Examples: | |||||||||||||||||||||||||||||
|
syntax
(#%module-begin form ...)
syntax
(#%top-interaction . form)