[plt-scheme] minor glitch in Lazy Scheme?

From: Eli Barzilay (eli at barzilay.org)
Date: Sat Jan 13 12:50:37 EST 2007

On Jan 13, Prabhakar Ragde wrote:
> Eli Barzilay wrote:
> > Like Matthias said -- that was exactly the point.  I wanted to
> > teach lazy evaluation, and the choices were (a) switch to Haskell,
> > (b) use lazy streams.  (a) is too strong of a change to make any
> > sense -- switching the syntax makes everything too confusing,
> > having it statically typed doesn't help too.  (b) is the
> > traditional solution, but I find it too weak when you want to
> > demonstrate laziness properly.
> 
> I'd appreciate any pedagogical examples of lazy evaluation for which
> streams are too weak -- I think I am just using standard examples
> (Fibonacci, sieve of Eratosthenes, Hamming numbers) for which they'd
> work fine. I was planning to briefly discuss delay and force (this
> would be in a single optional lecture, not something for credit or
> testable). --PR

One "weak" example that I had last semester is an exam question that I
put up on tmp.barzilay.org/x.html.  It's weak because you could do the
same with lazy streams, but it would be much more verbose & difficult,
which puts the stress in the wrong place.


Another example I had in an older test is the fact that throughout the
course they use a restricted `cons' that can only construct proper
lists.  This has the cute property that you can define `list?' as:

  (define (list? x)
    (or (null? x) (pair? x)))

When we get to the lazy language, I've encountered a dotted list by
accident: the thing is that you can't do

  (define (protected-cons x l)
    (unless (list? l)
      (error "bad args"))
    (cons x l))

one problem that I had at first (which made me the first victim of
this language) is that `unless' (being a function now) was creating a
promise that nobody forces -- since then I changed the behavior of the
implicit begin in function bodies to make the above equivalent to:

  (define (protected-cons x l)
    (if (list? l)
      (cons x l)
      (error "bad args")))

but that's not relevant since students can only use that second piece
of code.  In any case, that second piece of code is still bad: it's
too eager, which is not only inefficient, but it also excludes
infinite lists.  So the exam question was how to get out of this mess
and still don't allow improper list construction -- and the solution
is related to the above property, and is basically turning the test
into a contract in that it's delayed.

  (define (protected-cons x l)
    (cons x (if (or (null? l) (pair? l))
              l
              (error "..."))))


A third example is the way I'm explaining monads (no, not mentioning
the word "monad" or any other algebra terms).  Right after lazy
evaluation I'm covering macros -- and I usually combine both so the
end result is that they can run this code:

  (run-io
   "{with-stx {do @v{???}}
      {do {print 'What is your name?\\n'}
          {name <- {read}}
          {print 'What is your email?\\n'}
          {email <- {read}}
          {print 'Your address is '''}
          {print name}
          {print ' <'}
          {print email}
          {print '>''\\n'}}}")

Strictly speaking, this is not related to Lazy Scheme, since they do
that in the language that they implement -- but it would be very
difficult to explain how such things work if all they had experience
with is lazy streams.

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


Posted on the users mailing list.