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