[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme-reports] Formal Comment: what is the required behavior of 'lazy'?

10 minutes ago, Alex Shinn wrote:
> On Fri, Jun 29, 2012 at 10:15 AM, Eli Barzilay <eli@x> wrote:
> > A few minutes ago, Alex Shinn wrote:
> >> On Fri, Jun 29, 2012 at 9:32 AM, Eli Barzilay <eli@x> wrote:
> >> > Yesterday, Alex Shinn wrote:
> >> >> On Thu, Jun 28, 2012 at 1:39 AM, Eli Barzilay <eli@x> wrote:
> >> >> > A few minutes ago, Alex Shinn wrote:
> >> >> >> On Thu, Jun 28, 2012 at 1:12 AM, Eli Barzilay <eli@x> wrote:
> >> >> >> > With both present, there is an easy way to remember which one to
> >> >> >> > choose: `lazy'.
> >> >> >>
> >> >> >> `delay' is useful for many other things besides streams, where
> >> >> >> `lazy' would not be applicable.
> >> >> >
> >> >> > For example...?
> >> >>
> >> >> Do you honestly doubt that the concept of delayed
> >> >> evaluation has uses outside of a stream?
> >> >>
> >> >> In the most basic case it serves as a simple cache:
> >> >>
> >> >>   (let ((x (delay <expr>)))
> >> >>      ...
> >> >>      (if ... (force x) ...)
> >> >>      ...
> >> >>      (if ... (force x) ...))
> >> >>
> >> >> Lazy doesn't work here.
> >> >
> >> > *Some* `lazy's do.  I missed the fact that you've crippled `lazy'.
> >> > (It's an odd decision that not only makes it a more limited tool, it also
> >> > contradicts a dynamically typed language.)
> >>
> >> I'm only aware of one definition of `lazy' - the one from srfi-45
> >> and used by srfi-41.  If there is an alternative definition I'd like
> >> to know.
> >
> > It's one that does not require to be used with a promise.
> >
> > $ racket
> > Welcome to Racket v5.2.1.
> > -> (lazy 1)
> > #<promise:stdin:1:0>
> > -> (force ^)
> > 1
> > -> (force (lazy (lazy 2)))
> > 2
> (I assume Racket's repl binds ^ to the last result)


> The standard effectively allows but does not require this extension
> to lazy.

I don't know how that's the case -- I don't remember the exact wording
(and don't have the document now), but I remember it saying that
`lazy' should be used only on promises.  That's the crippling that I
was referring too, and if that's not the case it would be a good idea
to clarify that.

> However, that's not really the point here.  Lazy is still
> semantically difference from delay, because forcing a delay does not
> repeatedly force the result.

Yes, that is a difference between them.  I should revise my comment
then and say that `lazy' is good for many situations where you want to
delay some computation, and therefore you don't care about
differentiating a promise for a value from a promise holding a promise
for the same value.

> The transformation described by Wadler for converting a strict
> language into a lazy one naturally uses delay and force as a pair,
> and results in some compositions of delay and force, in addition to
> isolated delays.

That's not the only way to implement a lazy language -- and IIRC, the
conversion used in that paper is suitable for a strict language that
has some lazy definitions in it, and it suffers from over-strictness
in the bodies of lazy functions unless these bodies have only calls to
lazy functions themselves.  In any case, Lazy Racket implements
laziness in a somewhat different way, but neither implementation
should be related to the meaning of the `lazy' form.  The bottom line
in terms of understanding it is that `lazy' composes well with other
promises and effectively creates an alias of the input promise.  By
"an alias" I mean that the resulting promise is indistinguishable from
the original one: specifically, there is no loss of tail-position-ness
and there is no potential memory leakage due to such a loss.  A name
like "composable promise" is therefore much more mnemonic of the form,
if I was shooting for a meaningful name.  In this light, where
compositionality is the main feature of `lazy', and this
compositionality is lost when you use (delay (force ...)), it is clear
(or should be clear, IMO) why `delay-force' is a bad name.  It refers
to what it is "like" in a sort-of-*but* kind of way, which makes it a
bad analogy to a broken implementation.

> Lazy was introduced because existing implementations leak space in
> the delay+force compositions.

(Leak space is the byproduct of losing tail-ness.)

> However, the distinction is still useful, gives a finer grain of
> control over when promises are forced, and allows for cleaner type
> inference.

Yes, "cleaner type inference" was the motivation that made the srfi
author stick to the requirement, and my earlier comment is that this
kind of cleanliness is not needed in a dynamically typed language.  It
wouldn't hurt to add it, of course, but the resulting cost is that you
need to keep track of whether your expression will be a promise or an
actual value, and based on that you need to choose `lazy' or `delay'
-- this means that coding with the requirement for only promises in a
`lazy' form is harder, and contradicts the rest of the language.
Furthermore, the only purpose of `eager' in the srfi is to accomodate
the types: in a case where you need to "lift" a value to a promise but
you don't want the overhead of a redundant promise.  In an
implementation that allows `lazy' over values, there is simply no need
for such a construct -- which is another way which simplifies the
whole thing.

> Moreover, replacing delay with a permissive lazy would break
> existing programs.

(Yes, with double-delays.)

> Thus we need both in the standard, and the naming we've provided
> shows the relation clearly between the two while preserving
> consistency with R5RS and Wadler's paper.

See above about my unmoved opinion on the name, and more than that, I
don't see how `delay-force' is supposed to be more consistent with
R5RS.  `lazy' is doing something different from `delay' and that's it.
The current name is like calling a numeric identity function

> I understand we can't make everyone happy here, but I don't the the
> WG should spend time revisiting this naming yet again.  If you'd
> like to file a formal comment it will stand as a more visible
> objection, otherwise we'll try to be clear in the non-normative
> rationales that there was contention on this name.

Do whatever you want with this.  I do not intend to make a formal

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

Scheme-reports mailing list