[comp.lang.misc] Lazy evaluation vs. coroutines

ka@hropus.UUCP (Kenneth Almquist) (07/21/87)

Robert Rehbold states that one advantage of lazy evaluation is that
it is possible to use lazy evaluation to implement producer and
consumer functions.  Another way to do this is with coroutines.
To give an illustration of what can be done with coroutines, consider
how you would print out the elements of a binary tree in ICON:

	every element := twalk(tree) do
		write(element)

This gets the elements of the tree one by one and prints them.  If
a break statement were executed inside the loop, twalk would automatically
terminate without generating all the elements of the tree.  This is
a convenient way of writing a common case.  If you wanted to write a
routine that would compare two trees to see if they had the same elements
in the same order, you would explicitly start two copies of twalk and
then loop fetching elements from both trees until you found a discrepancy.

By the way, if you want to implement a producer/consumer pair, the best
approach is frequently not to combine the two into a single routine, but
rather to convert one of the routines into three routines:  an init
routine, a get or put routine, and a cleanup routine.  The local variables
of the original routine have to be made static or stored in a dynamicly
allocated structure.  For example, consider the triplet fopen/getc/fclose.
Fopen performs some initialization and returns the stack frame, getc
advances the execution of our hypothetical coroutine up to the point that
the next next character is generated, and fclose releases the resources
used by the coroutine.

Has anyone made any comparisons between lazy evaluation and coroutines?
I'm particularly interested in responses from someone who has written
programs using both.  Is one conceptually simpler than the other, or
better for program verification?  With coroutines, it is possible to
implement "servers" as well as plain data sources and sinks.  For example,
a coroutine implementation of a stdio input stream would actually have
to be implemented as a server which accepts several requests (getc,
fseek, feof, etc.) and send back the appropriate response.  Can you do
this with lazy evaluation?  I can envision implementing this as a
lazily evaluated tree, but the problem is that a program might, for
example, reference the fseek child of a node, and later referencing
the getc child of the same node in the tree.  This could be dealt with
by checkpointing the server at every transaction (potentially very
expensive), or by having the compiler detect and prohibit references
to multiple children of the same node (potentially impossible).
				Kenneth Almquist