[racket] lazy letrec-values

From: Eli Barzilay (eli at barzilay.org)
Date: Wed Jul 16 03:42:50 EDT 2014

I'm with #2 too, of course, but going the whole way and using MV
wrappers everywhere would be extremely expensive: you'd need to wrap
everything (including literals and identifiers (see earlier)), and the
!values is probably also substantial.

I forgot about something else that might work: IIRC, I originally
played with various different kinds of promises, including whether
they capture exceptions or not (which was expensive, but I left it in
since it seems more important) and whether they can deal with multiple
values or not.  I eventually settled on `delay' being able to spit out
multiple values, but `lazy' isn't, to reduce the cost.  So I don't
remember all of the details, but I've left a couple of comments about
places in the code (racket/private/promise) which take the
single-value-discount -- it might be good to try adding multiple
values to measure its performance penalty on one side, and to see if
it can solve the MV problem in LR without the wrapper hack.


On Mon, Jul 14, 2014 at 8:09 PM, Stephen Chang <stchang at ccs.neu.edu> wrote:
> The problem was that the values constructor in Lazy Racket had two
> different semantics, depending on the number of arguments, but the
> extractors (ie let-values and friends) only handled the latter. We
> should decide on one consistent behavior, mv's should either behave
> like:
>
> 1) tuples in a lazy language, or
> 2) racket values
>
> LR mv's already mostly behave like #1, and not like racket values. For
> example, (values 1 2) returns a multiple-values struct instance that
> can be passed around before extracting the values, something you
> cannot do in Racket. So it seems odd to me to enforce the Racket-like
> values behavior for only single-value values. The patch just makes all
> mv's consistently have the #1 behavior.
>
>> but now you get a different kind of
>> breakage where
>>
>>   (let-values ([(x) (values (error "a"))]) 1)
>>   (let-values ([(x)         (error "a") ]) 1)
>>
>> are not the same.
>
> If we want behavior #1, then these should not be the same, since you
> have to force down "one level" to get the shape, as Robby mentioned.
>
> If we want #2, the Racket-values behavior, then it seems to me like
> the right thing to do is to use !values everywhere instead of !. I
> understand not wanting to do so since it adds an extra check for every
> force, but since lazy Racket is not really performant enough for
> practical use, maybe this doesn't matter?
>
>
>
>> More than that, the hack of dealing with multiple
>> values is at such a (bad) level, that it's possible that the patch would
>> break code that assumes that `E' is equivalent to (values E).
>>
>> A more proper way to deal with `*-values' constructs would be for the
>> macro to treat a case of != 0 values differently from a single value, so
>> the force that breaks the above is not done.  That is, this kind of
>> change would make these two:
>>
>>     > (let-values ([(x) (values (error "poof"))]) 1)
>>     1 ; `values' doesn't wrap, but (x) means no !-ing
>>     > (let-values ([(x y) (values (error "poof"))]) 1)
>>     poof ; since now there are (x y) so the macro !s the RHS
>>
>> This is clearly not great either, but I think that overall it would be
>> more consistent.  (But of course it's not a 10-second fix.)
>>
>> (A much better way to deal with MVs is to have "TLR" (= TR+LR).)
>>
>> --
>>           ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
>>                     http://barzilay.org/                   Maze is Life!



-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.