[racket] lazy letrec-values

From: Stephen Chang (stchang at ccs.neu.edu)
Date: Fri Jul 11 18:02:04 EDT 2014

I merged. Thanks again!

> the interesting thing is that running
`./racket/bin/raco test pkgs/lazy` seems to pass even when I add a
failing test case such as  `(! (eq? 1 2)) => #t`.
That same test will fail as expected if I run it within drracket.

Thats because lazy currently doesn't use the "test" submodule. Running
"racket pkgs/lazy/tests/lang.rkt" shows all tests passing.


On Fri, Jul 11, 2014 at 4:00 PM, Luke Whittlesey
<luke.whittlesey at gmail.com> wrote:
> I just sent a pull request : https://github.com/plt/racket/pull/727
>
> I added a few simple test cases, but the interesting thing is that running
> `./racket/bin/raco test pkgs/lazy` seems to pass even when I add a failing
> test case such as  `(! (eq? 1 2)) => #t`.
> That same test will fail as expected if I run it within drracket.
>
> Thank you all for your time and help. (And thank you for creating such a
> nice community and toolset!)
>
> -Luke
>
>
>
>
>
>
> On Fri, Jul 11, 2014 at 12:02 AM, Spencer Florence
> <florence at northwestern.edu> wrote:
>>
>> It looks like he has taken those down. But I'm sure he would email a copy
>> if asked (the think is http://pl.barzilay.org/resources.html#classnotes btw)
>>
>>
>> On Thu, Jul 10, 2014 at 8:42 PM, Matthias Felleisen <matthias at ccs.neu.edu>
>> wrote:
>>>
>>>
>>> There are also Eli's class notes. I don't have a URL handy but I am sure
>>> if you google "Eli Barzilay" and "course" you'll find his notes on the
>>> various levels of lazy (plus homework assignments :-) -- Matthias
>>>
>>>
>>>
>>>
>>>
>>>
>>> On Jul 10, 2014, at 6:41 PM, Stephen Chang wrote:
>>>
>>> > Actually, this is a bug, because the expression in a single-argument
>>> > values call is forced prematurely.
>>> >
>>> > eg, This should not error:
>>> >
>>> > -> (let-values ([(x) (values (error "a"))]) 1)
>>> > ; a [,bt for context]
>>> >
>>> > Just like this does not error.
>>> >
>>> > -> (let-values ([(x y) (values (error "a") (error "b"))]) 1)
>>> > 1
>>> >
>>> > Lazy Racket is trying to preserve the (values x) == x from Racket, but
>>> > since LR's force is recursive, this is actually impossible without
>>> > breaking the semantics like it's doing now.
>>> >
>>> > Luke, thanks for finding this. If you want to submit a pull request, I
>>> > will merge. (Just drop the first clause in the case-lambda entirely.)
>>> > Maybe some extra tests would be nice as well :) Otherwise if you dont
>>> > have time, let me know and I'll do it.
>>> >
>>> >> Beyond the library documentation, does anyone know if there are any
>>> >> discussions or tutorials that go into the do's and don'ts of using #lang
>>> >> lazy ?
>>> >
>>> > There isnt any. You can check out the Barzilay-Clements paper [1] to
>>> > learn about the motivation behind LR, but otherwise LR should have
>>> > "standard" lazy semantics.
>>> >
>>> > [1]:
>>> > http://digitalcommons.calpoly.edu/cgi/viewcontent.cgi?article=1047&context=csse_fac
>>> >
>>> > On Thu, Jul 10, 2014 at 1:15 PM, Luke Whittlesey
>>> > <luke.whittlesey at gmail.com> wrote:
>>> >> Thank you for the in-depth analysis. Very interesting.
>>> >>
>>> >> Following your reasoning, if I edit lazy.rkt and force `values` to use
>>> >> `multiple-values` for the single entry case, the example that was
>>> >> previously
>>> >> broken now works. (I just have no idea if this breaks something else
>>> >> in the
>>> >> process.)
>>> >>
>>> >> at lazy.rkt line:223
>>> >> replace:
>>> >>  (define* ~values
>>> >>    (case-lambda [(x) x] [xs (multiple-values xs)]))
>>> >>
>>> >> with:
>>> >>  (define* ~values
>>> >>    (case-lambda [(x) (multiple-values (list x))] [xs (multiple-values
>>> >> xs)]))
>>> >>
>>> >>
>>> >> I had assumed that a reference to an identifier was delayed, so thanks
>>> >> for
>>> >> showing that this is currently not the case.
>>> >>
>>> >> Beyond the library documentation, does anyone know if there are any
>>> >> discussions or tutorials that go into the do's and don'ts of using
>>> >> #lang
>>> >> lazy ?
>>> >>
>>> >> Thanks,
>>> >> Luke
>>> >>
>>> >>
>>> >> On Thu, Jul 10, 2014 at 6:24 AM, Matthew Flatt <mflatt at cs.utah.edu>
>>> >> wrote:
>>> >>>
>>> >>> I'm not sure whether to call it a bug or a limitation of `lazy`.
>>> >>>
>>> >>> The `lazy` language doesn't delay a reference to an identifier. As a
>>> >>> result,
>>> >>>
>>> >>> (define x y)
>>> >>> (define y (list 1))
>>> >>> (car x)
>>> >>>
>>> >>> fails. The case could be made that the right-hand side of the
>>> >>> definition
>>> >>> of `x` should have been a lazy reference to `y`, but that's not what
>>> >>> `lazy` currently does.
>>> >>>
>>> >>> A problem with the current choice is that it interacts badly with
>>> >>> `!`,
>>> >>> especially as used by `letrec-values`. The implementation of
>>> >>> `letrec-values` forces the right-hand side of a binding using `!` to
>>> >>> determine how many values it produces. That works ok when the
>>> >>> right-hand side is produced by `values` on more than one argument,
>>> >>> because `values` produces a special multiple-values result that
>>> >>> leaves
>>> >>> its values unforced after `!`. When `values` get one argument, then
>>> >>> it
>>> >>> just returns the argument.... and that's still ok for something like
>>> >>> `(values (list 1 (/ 0)))`, because the `(/ 0)` expression is lazy.
>>> >>>
>>> >>> In your example, the implicit use of `!` for the right-hand side of
>>> >>> the
>>> >>> A` binding produces `(! (list a B))`. That `B` is not itself treated
>>> >>> as
>>> >>> a lazy expression, so forcing the list to be constructed causes `B`
>>> >>> to
>>> >>> be evaluated early.
>>> >>>
>>> >>> You can make the variable reference lazy by wrapping it with `~`:
>>> >>>
>>> >>>  (letrec-values ([(A) (values (list 'a (~ B)))]
>>> >>>                  [(B) (values (list 'b A))])
>>> >>>    B)
>>> >>>
>>> >>> Again, I don't know that you should have to do that, but it's how
>>> >>> `lazy` is defined at the moment.
>>> >>>
>>> >>> At Mon, 7 Jul 2014 15:06:26 -0400, Luke Whittlesey wrote:
>>> >>>> Hello all,
>>> >>>> I've been playing around with creating circular lists (and learning
>>> >>>> racket
>>> >>>> which has been quite fun), but I'm stumped on why the lazy version
>>> >>>> of
>>> >>>> letrec-values is not producing a promise like the lazy version of
>>> >>>> letrec
>>> >>>> does. With the lazy letrec I can create circular lists, but with the
>>> >>>> lazy
>>> >>>> letrec-values I get #<undefined>. See the example below.
>>> >>>>
>>> >>>> ;;;;;;;;;;;;;;;;; example code ;;;;;;;;;;;;;;;;;;;;;;;;;
>>> >>>> #lang lazy
>>> >>>>
>>> >>>> ;; create a circular list using letrec (this works)
>>> >>>> (define example-working
>>> >>>>  (letrec ([A (list 'a B)]
>>> >>>>           [B (list 'b A)])
>>> >>>>    B))
>>> >>>> (displayln "Working Example:")
>>> >>>> (displayln example-working)
>>> >>>> (displayln (!! example-working))
>>> >>>>
>>> >>>> ; Prints...
>>> >>>> ;Working Example:
>>> >>>> ;(b #<promise:A>)
>>> >>>> ;#0=(b (a #0#))
>>> >>>>
>>> >>>> ;; create a circular list using letrec-values (this is broken)
>>> >>>> (define example-broken
>>> >>>>  (letrec-values ([(A) (values (list 'a B))]
>>> >>>>                  [(B) (values (list 'b A))])
>>> >>>>    B))
>>> >>>> (displayln "Broken Example:")
>>> >>>> (displayln example-broken)
>>> >>>> (displayln (!! example-broken))
>>> >>>>
>>> >>>> ; Prints
>>> >>>> ;Broken Example:
>>> >>>> ;(b (a #<undefined>))
>>> >>>> ;(b (a #<undefined>))
>>> >>>> ;;;;;;;;;;;;;;;;; end code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>>> >>>>
>>> >>>> I realize that there are many different ways to generate circular
>>> >>>> lists,
>>> >>>> but why doesn't this work? Am I misunderstanding something or is
>>> >>>> this a
>>> >>>> bug?
>>> >>>>
>>> >>>> Thanks,
>>> >>>> Luke
>>> >>>> ____________________
>>> >>>>  Racket Users list:
>>> >>>>  http://lists.racket-lang.org/users
>>> >>
>>> >>
>>> >>
>>> >> ____________________
>>> >>  Racket Users list:
>>> >>  http://lists.racket-lang.org/users
>>> >>
>>> > ____________________
>>> >  Racket Users list:
>>> >  http://lists.racket-lang.org/users
>>>
>>>
>>> ____________________
>>>   Racket Users list:
>>>   http://lists.racket-lang.org/users
>>
>>
>>
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/users
>>
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>

Posted on the users mailing list.