[racket] making libraries work natively with both Racket & Typed Racket

From: Alexander D. Knauth (alexander at knauth.org)
Date: Sat Mar 21 18:55:39 EDT 2015

On Mar 21, 2015, at 2:09 PM, Matthew Butterick <mb at mbtype.com> wrote:

> Is there an approved way of using #lang typed/racket/base/no-check (or maybe `with-type`) to create libraries that have both a typed and untyped interface? (The goal being to avoid use of `require/typed`)

What I have done for measures-with-dimensions is write type code as normal typed file, but add an untyped submodule that
uses require/untyped-contract from typed/untyped-utils.  
I even made a macro to expand to this untyped submodule, which looks like this:
It expands to a module* that uses require/untyped-contract on the typed file with the simpler types for m*, m+, and m- (so that it can generate contracts for them), and requires and re-provides the other exports normally.  

That way an untyped file can require the untyped submodule, but I typed file can require either the typed file or the untyped submodule, and if an identifier from the untyped submodule is required into an untyped file and then back into another typed file, the type-checker knows what type it’s supposed to have, even though it came by way of an untyped module.  

For macros, I create an untyped file for the macro, where I require the untyped submodules of the files that has the things it expands into, and then provide the macro.
If the macro is used in untyped code, it expands to the things from the untyped submodules, but if it’s used in typed code, the type-checker knows what types they had originally in the typed file and uses those.  

There’s also define-typed/untyped-identifier if you need it, although the docs say to avoid it if possible and use require/untyped-contract where you can. Also, a macro can tell whether it’s being used in a typed context or not using syntax-local-typed-context?, if you need that.

Posted on the users mailing list.