[racket] Why Typed Racket is faster?

From: Vincent St-Amour (stamourv at ccs.neu.edu)
Date: Mon Feb 24 09:24:51 EST 2014

At Mon, 24 Feb 2014 13:51:30 +0800,
WarGrey Gyoudmon Ju wrote:
> Does RVM  know the type information at runtime? Is typed racket just a
> front-end parser (target to contracts)? In theory is it possible to
> manually optimize untyped racket to make it as fast as the typed one in
> most cases?

Typed Racket operates entirely at macro-expansion time. By the time the
Racket compiler sees a Typed Racket program, the types are all gone.

Typed Racket's optimizer simply rewrites operations to use unsafe
type-specific operations provided by Racket (see racket/unsafe/ops),
something you could do by hand if you wanted. TR also does some other
optimizations (scalar replacement, dead code elimination, etc.) which
you could also do by hand.

There are some advantages at having TR do it for you, though. First,
modulo bugs in TR, these "unsafe" operations are actually guaranteed to
actually be safe by the typechecker. If you manually add unsafe
operations, you may accidentally introduce segfaults. Second, TR
typechecks (and optimizes) code after macros are expanded, and so it can
optimize inside the expansion of macros, which you can't do at the
source level.

> To ignore the developing features, do we lose any expressivenesses?
> 
> (lambda ([μ 0.0] [σ 1.0] #:multiple [p 1])
>    (define samples (flnormal-sample μ σ p))
>    (apply  values (flvector->list samples))
> 
> This example returns non-fix-length multiple values,  it seems impossible
> to annotate its type.

That does indeed look like something TR does not support.

However, functions that return a variable number of values are often
(IMO) questionable design. I would recommend rewriting your code to
return a collection instead (and would recommend that even if TR was not
involved).

> It took me hours and hours to enumerate all possible ways but still
> unsolved.
> 
> (define: random-gaussian : (case-> [[#:mean Flonum] [#:stddev Flonum]
> [#:multiple False] -> Flonum]
>                                    [[#:mean Flonum] [#:stddev Flonum]
> [#:multiple Index] -> (Listof Flonum)])
>   {lambda {#:mean [μ 0.0] #:stddev [σ 1.0] #:multiple [p #false]}
>     (define: samples : FlVector (flnormal-sample μ σ (if (false? p) 1 p)))
>     (cond [(false? p) (flvector-ref samples 0)]
>           [else (flvector->list samples)])})
> 
> Actually, DrRacket complains about (Values Flonum)
> So 'multiple values' is evil!
> 
> Keyword argument is also the optional one, it's good for stopping (case->)
> becoming too complexity. But why not (false? p) tells Typed Racket to
> choose the first function types?

That's odd. I'll look into it.

Vincent


Posted on the users mailing list.