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.
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...)maybe-ret. body)
binding = [vare]| [var:typee]maybe-tvars =| #:forall(tvar...)| #:∀(tvar...)maybe-ret =| :type0
In the first form, maybe-ret can only appear with maybe-tvars, so if you only want to specify the return type, you should set maybe-tvars to #:forall().
- : Integer [more precisely: Zero]
0
- : Integer [more precisely: Zero]
0
eval:4:0: :: bad syntax
in: :
If polymorphic type variables are provided, they are bound in the type expressions for variable bindings.
- : Integer [more precisely: Zero]
0
In the second form, type0 is the type of the result of loop (and thus the result of the entire expression as well as the final expression in body). Type annotations are optional.
accum- : (Listof Nonnegative-Integer)
'(6 4 2)
(cond- : (Listof Nonnegative-Integer)
'(4 2)
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)
syntax
( lambda maybe-tvarsformalsmaybe-ret. body)
formals = (formal...)| (formal.... rst)formal = var| [vardefault-expr]| [var:type]| [var:typedefault-expr]| keywordvar| keyword[var:type]| keyword[var:typedefault-expr]rst = var| [var:type*]| [var:typeooobound]maybe-tvars =| #:forall(tvar...)| #:∀(tvar...)| #:forall(tvar...ooo)| #:∀(tvar...ooo)maybe-ret =| :type
- : (-> String String)
#<procedure>
- : (-> Any Integer Integer)
#<procedure>
- : (-> Any Any)
#<procedure>
Type annotations may also be specified for keyword and optional arguments:
- : (->* () (String) (String : (Top | Bot)))
#<procedure:eval:15:0>
- : (-> #:x String String)
#<procedure:eval:16:0>
- : (-> Any [#:y Integer] Integer)
#<procedure:eval:17:0>
- : (->* () (Any) Any)
#<procedure:eval:18:0>
The lambda expression may also specify polymorphic type variables that are bound for the type expressions in the formals.
- : (All (A) (-> A A))
#<procedure>
- : (All (A) (-> A A))
#<procedure>
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.
- : (-> Any Any * (Listof Any))
#<procedure>
- : (-> Any Integer * (Listof Integer))
#<procedure>
- : (All (A ...) (-> Any A ... A (List A ... A)))
#<procedure>
syntax
syntax
( case-lambda maybe-tvars[formalsbody]...)
Polymorphic type variables, if provided, are bound in the type expressions in the formals.
Note that each formals must have a different arity.
To see how to declare a type for add-map, see the case-> type constructor.
syntax
syntax
( for void-ann-maybe(for-clause...)void-ann-maybeexpr...+)
void-ann-maybe =| :Voidtype-ann-maybe =| :ufor-clause = [id:tseq-expr]| [(binding...)seq-expr]| [idseq-expr]| #:whenguard| #:unlessguard| #:do[do-body...]| break-clause| #:splice(splicing-id. form)binding = id| [id:t]break-clause = #:breakguard| #:finalguard
eval:29:0: :: bad syntax
in: :
- : False
#f
- : Boolean
#f
eval:32:0: Type Checker: type mismatch
expected: False
given: Boolean
in: #f
syntax
( for/list type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/hash type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/hasheq type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/hasheqv type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/hashalw type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/vector type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/or type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/sum type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/product type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/last type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/set type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/list type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/hash type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/hasheq type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/hasheqv type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/hashalw type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/vector type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/or type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/sum type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/product type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/last type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/set type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/and type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for/first type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/and type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
( for*/first type-ann-maybe(for-clause...)type-ann-maybeexpr...+)
syntax
([id:t]...maybe-result)(for-clause...)type-ann-maybeexpr...+)syntax
([id:tinit-expr]...maybe-result)(for-clause...)type-ann-maybeexpr...+)syntax
([id:tinit-expr]...maybe-result)(for-clause...)type-ann-maybeexpr...+)maybe-result =| #:resultresult-expr
Changed in version 1.11 of package typed-racket-lib: Added the #:result form.
Changed in version 1.12 of package typed-racket-lib: Added for/foldr .
syntax
( for* void-ann-maybe(for-clause...)void-ann-maybeexpr...+)
syntax
([id:t]...maybe-result)(for-clause...)type-ann-maybeexpr...+)syntax
([id:tinit-expr]...maybe-result)(for-clause...)type-ann-maybeexpr...+)syntax
([id:tinit-expr]...maybe-result)(for-clause...)type-ann-maybeexpr...+)maybe-result =| #:resultresult-expr
Changed in version 1.11 of package typed-racket-lib: Added the #:result form.
Changed in version 1.12 of package typed-racket-lib: Added for*/foldr .
syntax
(stop?-exprfinish-expr...)expr...+)step-expr-maybe =| step-expr
syntax
( define maybe-tvarsvmaybe-anne)
header = (function-name. formals)| (header. formals)formals = (formal...)| (formal.... rst)formal = var| [vardefault-expr]| [var:type]| [var:typedefault-expr]| keywordvar| keyword[var:type]| keyword[var:typedefault-expr]rst = var| [var:type*]| [var:typeooobound]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.
If polymorphic type variables are provided, then they are bound for use in the type annotation.
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.
The function definition form also allows curried function arguments with corresponding type annotations.
Note that unlike define from racket/base, define does not bind functions with keyword arguments to static information about those functions.
maybe-type-vars =| (v...)name-spec = name-id| name-idparentoptions = #:transparent| #:mutable| #:prefab| #:constructor-nameconstructor-id| #:extra-constructor-nameconstructor-id| #:propertyproperty-idproperty-expr| #:type-nametype-id
If type-id is not specified, name-id will be used for the name of the type associated with instances of the declared structure. Otherwise, type-id will be used for the type name, and using name-id in this case will cause a type error.
- : BigApple
#<apple>
eval:45:0: Type Checker: parse error in type;
type name `apple' is unbound
in: apple
type-id can be also used as an alias to name-id, i.e. it will be a transformer binding that encapsulates the same structure information as name-id does.
- : Avocado
#<avocado>
When parent is present, the structure is a substructure of parent.
When maybe-type-vars is present, the structure is polymorphic in the type variables v. If parent is also a polymorphic struct, then there must be at least as many type variables as in the parent type, and the parent type is instantiated with a prefix of the type variables matching the amount it needs.
Options provided have the same meaning as for the struct form from racket/base (with the exception of #:type-name, as described above).
A prefab structure type declaration will bind the given name-id or type-id to a Prefab type. Unlike the struct form from racket/base, a non-prefab structure type cannot extend a prefab structure type.
(Prefab a-prefab String)
eval:53:0: Type Checker: Error in macro expansion -- parent
type not a valid structure name: a-prefab
in: ()
Changed in version 1.4 of package typed-racket-lib: Added the #:type-name option.
syntax
( define-struct maybe-type-varsname-spec([f: t]...)options...)
maybe-type-vars =| (v...)name-spec = name-id| (name-idparent)options = #:transparent| #:mutable| #:type-nametype-id
Changed in version 1.4 of package typed-racket-lib: Added the #:type-name option.
syntax
( define-type nametmaybe-omit-def)
maybe-omit-def = #:omit-define-syntaxes|
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.
even-lst)- : (Even Integer)
'(1 2)
However, the recursive reference is only allowed when it is passed to a productive type constructor:
eval:58:0: Type Checker: Error in macro expansion -- parse
error in type;
not in a productive position
variable: Foo
in: Foo
eval:59:0: Type Checker: Error in macro expansion -- parse
error in type;
not in a productive position
variable: Bar
in: False
syntax
( make-predicate t)
syntax
( define-predicate namet)
The second form allows type annotations to elide one level of parentheses for function types.
syntax
( provide: [vt]...)
syntax
#{v:t}
If a dispatch macro on #\{ already exists in the current readtable, this syntax will be disabled.
syntax
( ann et)
syntax
#{e::t}
If a dispatch macro on #\{ already exists in the current readtable, this syntax will be disabled.
syntax
( cast et)
- : Integer
3
(cast for #f): broke its own contract
promised: string?
produced: 3
in: string?
contract from: cast
blaming: cast
(assuming the contract is correct)
at: eval:66:0
- : (-> String String)
#<procedure:val>
- : String
"hello"
The value is actually protected with two contracts. The second contract checks the new type, but the first contract is put there to enforce the old type, to protect higher-order uses of the value.
- : Any
"hello"
(cast for val): contract violation
expected: string?
given: 5
in: the 1st argument of
(-> string? any)
contract from: typed-world
blaming: cast
(assuming the contract is correct)
at: eval:70:0
cast will wrap the value e in a contract which will affect the runtime performance of reading and updating the value. This is needed when e is a complex data type, such as a hash table. However, when the type of the value can be checked using a simple predicate, consider using assert instead.
- : (Listof Integer)
'(4 3 2 1)
- : (Listof String)
'("4" "3" "2" "1")
- : Any
'("1" "2" "3" "4")
syntax
( row-inst erow)
- : (Class (field (x Integer)))
#<class:eval:84:0>
syntax
#{e@t...}
syntax
#{e@t...tooobound}
Here, m is a module spec, pred is an identifier naming a predicate, and maybe-renamed is an optionally-renamed identifier.
syntax
( require/typed mrt-clause...)
rt-clause = [maybe-renamedt]|struct-option...]|struct-option...]| [#:opaquetpred]maybe-renamed = id| (orig-idnew-id)maybe-tvars =| (type-variable...)struct-option = #:constructor-nameconstructor-id| #:extra-constructor-nameconstructor-id| #:type-nametype-id
The first case requires maybe-renamed, giving it type t.
The second and third cases require the struct with name name-id and creates a new type with the name type-id, or name-id if no type-id is provided, 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.
(elemleftright))
The fourth case defines a new opaque type t using the function pred as a predicate. (Module m must provide pred and pred must have type (Any -> Boolean ).) The type t is defined as precisely those values that pred returns #t for. Opaque types must be required lexically before they are used.
> evt?- : (-> Any Boolean : Evt)
#<procedure:evt?>
- : Any
#<alarm-evt>
The #:signature keyword registers the required signature in the signature environment. For more information on the use of signatures in Typed Racket see the documentation for typed/racket/unit.
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 .
file-or-directory-modify-seconds has some arguments which are optional, so we need to use case-> .
Changed in version 1.4 of package typed-racket-lib: Added the #:type-name option.
Changed in version 1.6: Added syntax for struct type variables, only works in unsafe requires.
Changed in version 1.12: Added default type Any for omitted inst args.
syntax
( require/typed/provide mrt-clause...)
syntax
syntax
Added in version 1.12 of package typed-racket-lib.
procedure
;typed, and thus contracted, prompt tag;the function cannot be passed an argumentdefault-continuation-prompt-tag: broke its own contract
Attempted to use a higher-order value passed as `Any` in
untyped code: #<procedure>
in: the range of
(-> (prompt-tag/c Any #:call/cc Any))
contract from: untyped
blaming: untyped
(assuming the contract is correct)
syntax
( #%module-begin form...)
syntax
( #%top-interaction . form)
#:propertyprop:procedure- : (∩ (-> Number Number) animal)
#<procedure:add1>
#:propertyprop:procedure> (plant31)- : (∩ (-> String Number) plant)
#<procedure:plant>
In other words, a variable that refers to a function is not allowed
Unlike in Racket, only one of the following types of expressions are allowed in Typed Racket: a nonnegative literal, (struct-index-fieldfield-name), or a lambda expression. Note that in the last case, if the type annotation on the codomain is not supplied, the type checker will use Any as the return type.
Similar to other structure type properties, when a structure’s base structure specifies a value for prop:procedure , the structure inherits that value if it does not specify its own.
- : (∩ (-> Number Number) cat)
#<procedure:add1>
- : (∩ (-> Number Number) a-cat)
#<procedure:add1>
Function types for procedural structures do not enforce subtyping relations. A substructure can specify a different field index or a procedure that has a arity and/or types different from its base structures for prop:procedure .
- : (∩ (-> Number String) b-cat)
#<procedure:number->string>