On this page:
5.1 Untyped Utilities
require/  untyped-contract
define-typed/  untyped-identifier

5 Utilities

Typed Racket provides some additional utility functions to facilitate typed programming.


(assert v)  A

  v : (U #f A)
(assert v p?)  B
  v : A
  p? : (A -> Any : B)
Verifies that the argument satisfies the constraint. If no predicate is provided, simply checks that the value is not #f.

See also the cast form.


> (define: x : (U #f String) (number->string 7))
> x

- : (U False String)


> (assert x)

- : String


> (define: y : (U String Symbol) "hello")
> y

- : (U Symbol String)


> (assert y string?)

- : String


> (assert y boolean?)

- : Any [more precisely: Nothing]

Assertion #<procedure:boolean?> failed on "hello"


(with-asserts ([id maybe-pred] ...) body ...+)

maybe-pred = 
  | predicate
Guard the body with assertions. If any of the assertions fail, the program errors. These assertions behave like assert.


(defined? v)  boolean?

  v : any/c
A predicate for determining if v is not #<undefined>.


(index? v)  boolean?

  v : any/c
A predicate for the Index type.


(typecheck-fail orig-stx maybe-msg maybe-id)

maybe-msg = 
  | msg-string
maybe-id = 
  | #:covered-id id
Explicitly produce a type error, with the source location or orig-stx. If msg-string is present, it must be a literal string, it is used as the error message, otherwise the error message "Incomplete case coverage" is used. If id is present and has type T, then the message "missing coverage of T" is added to the error message.


> (define-syntax (cond* stx)
    (syntax-case stx ()
      [(_ x clause ...)
       #`(cond clause ... [else (typecheck-fail #,stx "incomplete coverage"
                                                #:covered-id x)])]))
> (define: (f [x  : (U String Integer)]) : Boolean
    (cond* x
           [(string? x) #t]
           [(exact-nonnegative-integer? x) #f]))

eval:10:0: Type Checker: incomplete coverage; missing

coverage of Negative-Integer

  in: #f

5.1 Untyped Utilities

 (require typed/untyped-utils)
  package: typed-racket-more

These utilities help interface typed with untyped code, particularly typed libraries that use types that cannot be converted into contracts, or export syntax transformers that must expand differently in typed and untyped contexts.


(require/untyped-contract maybe-begin module [name subtype] ...)

maybe-begin = 
  | (begin expr ...)
Use this form to import typed identifiers whose types cannot be converted into contracts, but have subtypes that can be converted into contracts.

For example, suppose we define and provide the Typed Racket function
(: negate (case-> (-> Index Fixnum)
                  (-> Integer Integer)))
(define (negate x) (- x))
Trying to use negate within an untyped module will raise an error because the cases cannot be distinguished by arity alone.

If the defining module for negate is "my-numerics.rkt", it can be imported and used in untyped code this way:
 [negate  (-> Integer Integer)])
The type (-> Integer Integer) is converted into the contract used for negate.

The require/untyped-contract form expands into a submodule with language typed/racket/base. Identifiers used in subtype expressions must be either in Typed Racket’s base type environment (e.g. Integer and Listof) or defined by an expression in the maybe-begin form, which is spliced into the submodule. For example, the math/matrix module imports and reexports matrix-expt, which has a case-> type, for untyped use in this way:
(provide matrix-expt)
 (begin (require "private/matrix/matrix-types.rkt"))
 [matrix-expt  ((Matrix Number) Integer -> (Matrix Number))])
The (require "private/matrix/matrix-types.rkt") expression imports the Matrix type.

If an identifier name is imported using require/untyped-contract, reexported, and imported into typed code, it has its original type, not subtype. In other words, subtype is used only to generate a contract for name, not to narrow its type.

Because of limitations in the macro expander, require/untyped-contract cannot currently be used in typed code.


(define-typed/untyped-identifier name typed-name untyped-name)

Defines an identifier name that expands to typed-name in typed contexts and to untyped-name in untyped contexts. Each subform must be an identifier.

Suppose we define and provide a Typed Racket function with this type:

(: my-filter (All (a) (-> (-> Any Any : a) (Listof Any) (Listof a))))

This type cannot be converted into a contract because it accepts a predicate. Worse, require/untyped-contract does not help because (All (a) (-> (-> Any Any) (Listof Any) (Listof a))) is not a subtype.

In this case, we might still provide my-filter to untyped code using
(provide my-filter)
(define-typed/untyped-identifier my-filter
where typed:my-filter is the original my-filter, but imported using prefix-in, and untyped:my-filter is either a Typed Racket implementation of it with type (All (a) (-> (-> Any Any) (Listof Any) (Listof a))) or an untyped Racket implementation.

Avoid this if possible. Use only in cases where a type has no subtype that can be converted to a contract; i.e. cases in which require/untyped-contract cannot be used.

Returns #t if called while expanding code in a typed context; otherwise #f.

This is the nuclear option, provided because it is sometimes, but rarely, useful. Avoid.