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

Re: [Scheme-reports] Some comments after reading the r7rs public draft

Hash: SHA1

On 06/06/2012 07:31 PM, Mark H Weaver wrote:
> John Cowan <cowan@x> writes:

>> It seems clear that having `delay` spawn a background thread is
>> consistent with the R5RS/R7RS definition of `delay`, so I have
>> added the following editorial remark:
>> # This behavior may be implemented in a variety of ways, #
>> including the return of a thunk which `force` will evaluate # to
>> the creation of a background thread to do the computation.
> This has the potential to break existing code for at least two
> reasons:
> (1) It means that the delayed expression may be evaluated even if
> the promise is never forced.  Therefore, programs which are
> designed with the assumption that unforced promises will never be
> evaluated will do a lot of unnecessary computation and possibly
> become unusable.
> (2) It means that if the delayed expression mutates any shared
> state, thread synchronization primitives will now be needed.  Since
> such primitives are not present in R7RS-small, it will be
> impossible to use 'delay' and 'force' in a portable R7RS-small
> program.  Even if such primitives are added, it means that portable
> programs will need to assume that such (very expensive)
> synchronization primitives must be used.

Scheme's "delay" and "force" have never really made strong enough
guarantees that delayed promises will not be computed unless
forced.  The language allows implicit forcing whenever a promise
is referred to.  This makes it impossible to do anything else
with a promise.  You can't even portably write a function to
tell whether something is a promise or not, because you can't
reliably pass it unevaluated as an argument to such a function.
The only semantics for which this is the "correct" behavior
are pure-functional promises, ie, computations with no side
effects. Similarly, the only arguments for which Scheme's
undefined argument evaluation order is the "correct" behavior
are pure-functional arguments, ie, computations with no side
effects.  It's consistent, but because at least some expressions
must have side effects, it's maddening.

For that reason, I have never found these primitives very useful.
If you have a promise that will cause a side effect when forced,
in Scheme you usually have something that will produce inconsistent
behavior across different implementations, and sometimes even
across different runs in the same implementation.

Unless guarantees of circumstances in which there is NOT forcing
are strengthened, "delay" and "force" are simply not very useful.
On the other hand, if no such guarantees are made, then the
proposed extension (speculative and/or background forcing) is
consistent with the language definition - even though it violates
the "principle of least astonishment" with regard to things that
were delayed because of possible side effects or divergence.

I sometimes think that promises ought to cause an implicit
try/catch, in that expressions involving one promise are tried,
then if they result in type errors, caught and tried again
with the result of forcing the promise.  But then I think
about what that means for expressions involving more than one
promise, and I get a headache because the order-of-forcing
arguments invokes the same nondeterminism as the
order-of-evaluating arguments in regular procedure calls.

Still, it would be nice to have some hard rules, like, "in
a context where a string or number is required, if a function
receives a promise it will force that promise; otherwise it
will not."  And beyond that kind of explicitly type-driven
expansion require a "force" to force arguments.



Version: GnuPG v1.4.12 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/


Scheme-reports mailing list