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

From: Matthew Butterick (mb at mbtype.com)
Date: Sat Mar 21 14:54:49 EDT 2015

1) You can't ordinarily use a macro from a typed module in untyped code.
But with this technique, if you convert `fladd` to a macro, it will still
work.

2) You can't ordinarily eliminate contract checks when using typed code in
untyped code, because a contract is always erected at the boundary. But
with this technique, if you remove the contract from "untyped.rkt", it will
still work. Then, you have three choices for how to use the function: fully
typed (in typed code), with contract (in untyped code), or no contract (in
untyped code).

The point of all this is to take libraries I've already written for untyped
Racket and optimize them for typed use, without sacrificing anything on the
untyped side (and without creating a duplicate typed codebase).

I've done something similar in the past where I've written my main module
functions without contracts, and then put the contracts inside a submodule
called (module+ safe ... ). Then then module can be required from other
modules either with or without contracts. It works correctly and it's
useful.



On Sat, Mar 21, 2015 at 11:23 AM, Alexis King <lexi.lambda at gmail.com> wrote:

> Sorry for my misunderstanding, but what’s the point of this? Why not just
> require the typed code in untyped code directly (as you’re doing in
> 'violator)? As far as I can tell, it looks like you’re just manually
> rewriting the generated contracts, so I’m not really sure what this
> achieves.
>
> > On Mar 21, 2015, at 11:09, 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`)
> >
> > For instance, the following works, but maybe it's a bad idea for other
> reasons:
> >
> > ;;;;;;;;;;;;;;;;;;;
> >
> > ;; adder.rkt = write typed code, but leave off #lang line & `provide`
> >
> > (: fladd (Flonum Flonum . -> . Flonum))
> > (define (fladd f1 f2)
> >  (+ f1 f2))
> > ;;;;;;;;;;;;;;;;;;;
> >
> >
> > ;;;;;;;;;;;;;;;;;;;
> >
> > ;; typed.rkt = compile in typed context
> >
> > #lang typed/racket/base
> > (require racket/include)
> > (provide fladd)
> > (include "adder.rkt")
> > ;;;;;;;;;;;;;;;;;;;
> >
> >
> > ;;;;;;;;;;;;;;;;;;;
> >
> > ;; untyped.rkt = compile in untyped context with contract
> >
> > #lang typed/racket/base/no-check
> > (require racket/include racket/contract racket/math)
> > (provide (contract-out [fladd (flonum? flonum? . -> . flonum?)]))
> > (include "adder.rkt")
> > ;;;;;;;;;;;;;;;;;;;
> >
> >
> > ;;;;;;;;;;;;;;;;;;;
> >
> > ;; test.rkt
> >
> > #lang racket/base
> >
> > (module typed typed/racket/base
> >  (require "typed.rkt")
> >  (require typed/rackunit)
> >  (check-equal? (fladd 1.0 2.0) 3.0)) ; typechecks correctly
> >
> > (module untyped racket/base
> >  (require "untyped.rkt")
> >  (require rackunit)
> >  (check-equal? (fladd 1.0 2.0) 3.0) ; meets `provide` contract
> >  (check-exn exn:fail:contract? (λ () (fladd 1 2)))) ; violates `provide`
> contract
> >
> > (module violator racket/base
> >  (require "typed.rkt")
> >  (require rackunit)
> >  (check-exn exn:fail:contract? (λ () (fladd 1 2)))) ; violates
> typed/untyped contract barrier
> >
> > (require 'typed)
> > (require 'untyped)
> > (require 'violator)
> > ;;;;;;;;;;;;;;;;;;;
> >
> >
> > ____________________
> >  Racket Users list:
> >  http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20150321/26a2b7e0/attachment-0001.html>

Posted on the users mailing list.