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.whittle...@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 <mfl...@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