[racket] Multiple return values
On 12/15/2011 05:03 AM, Markku Rontu wrote:
> Named return values, ah the dream of symmetry.
I think my mad-scientist advisor did something like this once. I think
it would be awesome to have this, and of course keyword arguments, as
first-class constructs in Racket.
(As far as I understand, the macros that expand lambdas with keyword
arguments would be a major PITA to write in C, and would be almost
certainly buggy for years. We'll need a bootstrapping compiler first.)
Anyway, back to the question. Symmetry + GENERALITY is one main reason.
A first-class continuation acts a lot like a procedure. Generalizing a
bit, continuations should take multiple arguments. Invoking a
multiple-argument continuation is equivalent to returning multiple
values to the spot it was captured; we therefore need multiple values if
we want to generalize continuations.
Another reason is efficiency. I'm writing a simple ray tracer for 2D
image + depth-map effects. (Think shiny icons, logos and slideshows.)
Here's my code for extracting the min and max values from a depth map:
(define (flimage-extrema img)
(match-define (flimage vs d w h) img)
(for/fold ([v-min 0.0] [v-max 0.0]) ([v (in-flvector vs)])
(values (unsafe-flmin v-min v)
(unsafe-flmax v-max v))))
This, like all the other ray tracer code, has to run fast. In general,
getting good speed means 1) no boxing flonums; and more generally 2) no
allocating. If I didn't have multiple values I'd have three options:
A. Use mutation. Fast enough but undesirable. Makes code harder for
me and the compiler to reason about.
B. Put them in a pair or list. Slow. Allocates a container and boxes
the flonums `v-min' and `v-max' in every iteration.
C. Make two passes. Duplicates code and computations. Makes me cranky.
As it is, I believe Racket's JIT can prove that no flonums need boxing,
so this loop avoids allocation entirely.
Neil T