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