[racket-dev] What are single flonums good for?

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Sun Sep 16 18:10:01 EDT 2012

Suppose we had started Racket long ago and maintained it until now. Then we'd be looking at 8bit, 16, 32, and 64 precision. In some N years from now, we may need 128. (Actually there were machines in the past that did, but never mind.) 

Could we separate precision and type into separate dimensions so that we could state types like this: 

  ∀ p : precision. FP[p] -> FP[p] 

where we see FP as a type constructor that consumes a precision value to generate the right kind of type. This might be a dependent type but it could be a useful one. Of course, it isn't really a parametric form of polymorphism as Neil's functions show (and better still Vincent's rewrites). 

-- Matthias



 


On Sep 15, 2012, at 9:31 AM, Vincent St-Amour wrote:

> At Fri, 14 Sep 2012 23:45:43 -0500,
> Robby Findler wrote:
>> The original message in this thread suggests that there is a type
>> Single-Flonum and that it is making Neil wrangle his code to be
>> careful about it.
> 
> Right, TR supports `Single-Flonum's, but not `f32vector's.
> 
> Part of the complexity in Neil's code is due to types, part of it is not.
> 
> Assuming he wrote the math library in untyped Racket:
> 
>    (define (foo x)
>       (cond [(double-flonum? x)  (flfoo x)]
>             [(single-flonum? x)  (real->single-flonum
>                                   (flfoo (real->double-flonum x)))]
>             [else  (flfoo (real->double-flonum x))]))
> 
> The code is exactly the same as before. The complexity comes from the
> fact that this function, when given single-precision inputs, wants to
> produce single-precision outputs, hence the special case.
> 
> If Neil wants `foo' to be as flexible as Racket's built-in operations
> (which, when given single-precision inputs, produce single-precision
> outputs), he needs that special case, types or not.
> 
> If he gives up on that flexibility, things become a lot simpler:
> 
>    (define (foo x)
>       (flfoo (real->double-flonum x)))
> 
> This version still accepts single-precision inputs, but always produces
> doubles.
> 
> The types simply mirror that distinction:
> 
>    (: foo (case-> (Single-Flonum -> Single-Flonum)
>                    (Flonum -> Flonum)
>                    (Real -> Real)))
> 
> vs
> 
>    (: foo (Real -> Flonum))
> 
> This kind of complexity gets worse for functions with multiple arguments,
> and types make it worse. When expressing coercion rules, the
> implementation can take shortcuts that the type system cannot currently
> express, leading to unwieldy types.
> 
> These issues only come up when writing libraries that aim to propagate
> Racket's numeric flexibility, such as the math library or TR's base
> environment. Clients of either don't need to worry about any of that.
> 
> Single-precision floats are not the source of this problem (you would
> run into the same issues, in both the untyped and typed worlds, with a
> function that takes ints to ints and floats to floats), but they do add
> one more type to worry about.
> 
> Vincent
> _________________________
>  Racket Developers list:
>  http://lists.racket-lang.org/dev



Posted on the dev mailing list.