[racket] lazy letrec-values

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Fri Jul 11 19:56:04 EDT 2014

You should probably change this so that drdr runs the right tests.
Changing the module+ main to module+ test is probably the way to go.

Robby


On Fri, Jul 11, 2014 at 5:02 PM, Stephen Chang <stchang at ccs.neu.edu> wrote:
> 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
>>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.