Documented typed/untyped-utils

original commit: d68786555695ec197ffc3dcd31e783beb36f348e
This commit is contained in:
Neil Toronto 2014-04-04 19:02:32 -06:00
parent 58b694fff1
commit 8e5b550ee8

View File

@ -1,7 +1,8 @@
#lang scribble/manual
@begin[(require "../utils.rkt" scribble/eval racket/sandbox)
(require (for-label (only-meta-in 0 [except-in typed/racket for])))]
(require (for-label (only-meta-in 0 [except-in typed/racket for])
typed/untyped-utils))]
@(define the-eval (make-base-eval))
@(the-eval '(require (except-in typed/racket #%top-interaction #%module-begin)))
@ -71,5 +72,94 @@ the error message.
}
@section{Untyped Utilities}
@defmodule[typed/untyped-utils]
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.
@defform*/subs[[(require/untyped-contract maybe-begin module [name subtype] ...)]
([maybe-begin code:blank (code:line (begin expr ...))])]{
Use this form to import typed identifiers whose types cannot be converted into
contracts, but have @emph{subtypes} that can be converted into contracts.
For example, suppose we define and provide the Typed Racket function
@racketblock[(: negate (case-> (-> Index Fixnum)
(-> Integer Integer)))
(define (negate x) (- x))]
Trying to use @racket[negate] within an untyped module will raise an error
because the cases cannot be distinguished by arity alone.
If the defining module for @racket[negate] is @racket["my-numerics.rkt"],
it can be imported and used in untyped code this way:
@racketblock[(require/untyped-contract
"my-numerics.rkt"
[negate (-> Integer Integer)])]
The type @racket[(-> Integer Integer)] is converted into the contract used
for @racket[negate].
The @racket[require/untyped-contract] form expands into a submodule
with language @racketmodname[typed/racket/base]. Identifiers used in
@racket[subtype] expressions must be either in Typed Racket's base type
environment (e.g. @racket[Integer] and @racket[Listof]) or defined by an
expression in the @racket[maybe-begin] form, which is spliced into the
submodule. For example, the @racketmodname[math/matrix] module imports and
reexports @racket[matrix-expt], which has a @racket[case->] type,
for untyped use in this way:
@racketblock[(provide matrix-expt)
(require/untyped-contract
(begin (require "private/matrix/matrix-types.rkt"))
"private/matrix/matrix-expt.rkt"
[matrix-expt ((Matrix Number) Integer -> (Matrix Number))])]
The @racket[(require "private/matrix/matrix-types.rkt")] expression imports the
@racket[Matrix] type.
If an identifier @racket[name] is imported using @racket[require/untyped-contract],
reexported, and imported into typed code, it has its original type, not
@racket[subtype]. In other words, @racket[subtype] is used only to generate
a contract for @racket[name], not to narrow its type.
Because of limitations in the macro expander, @racket[require/untyped-contract]
cannot currently be used in typed code.
}
@defform[(define-typed/untyped-identifier name typed-name untyped-name)]{
Defines an identifier @racket[name] that expands to @racket[typed-name] in typed
contexts and to @racket[untyped-name] in untyped contexts. Each subform must be
an identifier.
Suppose we define and provide a Typed Racket function with this type:
@racketblock[(: 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, @racket[require/untyped-contract] does not help because
@racket[(All (a) (-> (-> Any Any) (Listof Any) (Listof a)))] is not a subtype.
In this case, we might still provide @racket[my-filter] to untyped code using
@racketblock[(provide my-filter)
(define-typed/untyped-identifier my-filter
typed:my-filter
untyped:my-filter)]
where @racket[typed:my-filter] is the original @racket[my-filter], but imported
using @racket[prefix-in], and @racket[untyped:my-filter] is either a Typed Racket
implementation of it with type @racket[(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 @racket[require/untyped-contract]
cannot be used.
}
@defproc[(syntax-local-typed-context?) boolean?]{
Returns @racket[#t] if called while expanding code in a typed context; otherwise
@racket[#f].
This is the nuclear option, provided because it is sometimes, but rarely, useful.
Avoid.
}
@(close-eval the-eval)
@(close-eval the-top-eval)