Files
mercury/extras/lazy_evaluation
Fergus Henderson dced016cc1 Fix a problem where different packages in the `extras' distribution
Estimated hours taken: 3
Branches: main, release

Fix a problem where different packages in the `extras' distribution
were being installed in different directories when you specified
INSTALL_PREFIX in the Mmake.params file.  Some honoured the INSTALL_PREFIX
setting, some appended "/extras", and some ignored it completely.

Also, add `clean' and `realclean' targets for the extras directory hierarchy,
and fix a few other minor bugs.

extras/lazy_evaluation/Mmakefile:
	Include Mmake.params, which previously wasn't included at all
	in this file.

extras/logged_output/Mmakefile:
extras/odbc/Mmakefile:
extras/quickcheck/Mmakefile:
	Append "/extras" to INSTALL_PREFIX, which previously wasn't done
	at all in these directories.

extras/cgi/Mmakefile:
extras/complex_numbers/Mmakefile:
extras/concurrency/Mmakefile:
extras/curs/Mmakefile:
extras/curses/Mmakefile:
extras/dynamic_linking/Mmakefile:
extras/moose/Mmakefile:
extras/posix/Mmakefile:
	Move the line `INSTALL_PREFIX := $(INSTALL_PREFIX/extras)'
	to before the include of Mmake.params, so as not to override
	the user's setting (only override the default setting).

extras/Mmakefile:
extras/concurrency/Mmakefile:
	Add `clean' and `realclean' targets.

extras/posix/Mmakefile:
	Add MGNUCFLAGS = --no-ansi, since this is needed on some systems.

extras/quickcheck/Mmakefile:
	Add "depend", "all", and "install" targets.
	Ensure that the "check" target runs the test program.

extras/quickcheck/qcheck.m:
	Set the exit status to non-zero if a test fails.

extras/references/Mmakefile:
	Adjust the setting of LIBGRADES to account for the fact that
	$(GRADE) is no longer implicitly included in $(LIBGRADES).
2003-01-16 10:44:26 +00:00
..

This directory contains support for optional lazy evaluation.
Using the modules defined here, you can write Mercury code that
makes use of lazily evaluated data structures. 

Our implementation of lazy evaluation requires you to use a different
type, lazy(T), whenever you want things to be lazily evaluated, and
requires you to insert explicit calls to delay/1 or force/1 whenever
lazy evaluation requires the creation or evaluation of closures.

This directory contains the following files:

	lazy.m:
		This module defines the lazy(T) type, and the force/1
		and delay/1 functions.

	lazy_list.m:
		This module defines a type lazy_list(T) using the lazy(T) type,
		and also defines a few functions and predicates that operate
		on lazy lists.

	lazy_list_test.m:
		This is just a very simple example showing the use of lazy
		lists.

In comparison with lazy functional languages, the disadvantage of our
approach is that inserting the lazy(T) types and the explicit calls to
force/1 and delay/1 requires additional work when you are writing your
code.  Fortunately the Mercury compiler's static type checking will
ensure that the calls to force/1 and delay/1 are consistent with the
use of lazy(T) types.  But even so, putting all the calls to force/1
and delay/1 in the right place can still be rather tedious. 

In return, however, we get several important advantages.

The first is that there are absolutely no efficiency costs resulting
from lazy evaluation if you don't use it.  This is in contrast to many
implementations of lazy functional languages, where you often pay a
significant efficiency cost simply because things *might* be lazy, even
when in actual fact they are not.  Compilers for lazy functional
languages often try to avoid these costs by performing strictness
analysis, but current compilers can only infer strictness of functions,
not data types; using lazy data types rather than strict data types can
have a very large impact on efficiency (e.g. a factor of 5).  Also, in
the presence of separate compilation, compilers may need to make
conservative assumptions about strictness.

The second advantage is that the creation and evaluation of closures is
explicit in the source code, which makes it much easier to reason about
the performance of your programs.  Programs in languages where laziness
is the default often suffer from space leaks or unexpectedly high
memory usage, and these problems can be _extremely_ difficult to track
down and understand, even for very experienced programmers.

The third advantage is that supporting lazy evaluation via a library
module keeps the language and its semantics simple.  We're not really
providing lazy evaluation per se, we just _emulating_ it by passing
lambda expressions as arguments.  So the "Semantics" chapter of the
language reference manual does not need to be modified at all.
Supporting lazy evaluation via a library module also keeps the
implementation simple -- the module lazy.m requires only a very
small amount of implementation-dependent code, and none of the
rest of the implementation need change.

Our current implementation of lazy evaluation is not very efficient.
There are several reasons for this.  One is that promise_only_solution/1,
which is used in the implementation of force/1, is currently implemented
rather inefficiently.  Another is that the lazy(T) type currently uses
two levels of indirection, whereas it really ought to use only one.
Finally, for maximum efficiency, we would need to inline delay/1,
but that is not possible in the current implementation.  Solving these
latter two issues would require a bit more compiler support.