This library had been neglected for a while and came to my attention when it
used deprecated (or at least old) C interfaces rather than newer reentrant
ones. I've started to improve this library by giving a more typesafe and
Mercury-esque API, using only reentrant C functions, and eventually adding
support for more protocols, (eg: IPv6 and UDP) better integration with
Mercury's io module and generally making it easier to use.
What's working now:
+ creating sockets,
+ binding and listening,
+ connecting (untested),
+ accepting,
+ closing.
+ The interface is generally more type-safe, using new types suck as
"socket" and "address" rather than "int" and "c_pointer".
What's not working/incomplete:
+ I havn't yet touched the tcp.m module, but I intend to remove it and
create a new high-level interface for various protocols.
+ Any kind of reading / writing over sockets at all.
+ Name lookups.
+ A lot of the interface is incomplete / missing useful functions and
predicates.
This is a work in progress.
Makefile:
New Makefile.
README.md:
New Readme file.
net.m:
net is now a module containing the other modules as submodules.
sockets.m:
Many changes as described above.
netdb.m:
This new module contains host and other name lookups. Only service
lookups are currently implemented.
types.m:
Types shared by sockets.m and netdb.m.
echo.m:
An example echo server.
errno.m:
strerror functionality.
tcp.m:
Conform to changes in net.m.
sockets.m:
This file used a static C variable to store the most recent value of
errno. This has been removed and replaced with better return values
making more calls thread safe. Some non-thread safe calls still remain
where the C library call itself is not thread safe.
This change fixes two problems with the net library in extras/.
The h_addr field of the hostent structure (see gethostbyname(3)) is
deprecated. gethostbyname can return multiple addresses in a list in the
field h_addr_list. I've updated code to use the first item in this list.
Note that use of gethostbyname is also discouraged and getaddrinfo(3) is
recommended. In a later change I intend to update this library to use
getaddrinfo.
The library used a macro error() to retrieve the error either from errno, or
on Windows from WSAGetLastError. WSAGetLastError is a function however the
parentheses were missing from the macro causing it to be returned as a value
rather than called.
extras/net/sockets.m:
extras/net/tcp.m:
As above.
Add MR_strerror as a thread-safe alternative to strerror.
The current implementation wraps strerror_r(), strerror_s()
or sys_errlist as appropriate for the platform. Bug #340.
configure.ac:
runtime/mercury_conf.h.in:
Check for strerror_r, strerror_s.
Delete irrelevant code in the sockets test for the external debugger.
runtime/mercury_runtime_util.c:
runtime/mercury_runtime_util.h:
Add MR_strerror and use it.
library/io.m:
Use MR_strerror. In particular, mercury_output_error was not
thread-safe.
Pass errno to mercury_output_error explicitly for clarity.
Delete req_lock parameter in ML_maybe_make_err_msg macro which is not
needed any more.
compiler/prog_event.m:
runtime/mercury_deep_profiling.c:
runtime/mercury_misc.c:
runtime/mercury_term_size.c:
runtime/mercury_trace_base.c:
trace/mercury_trace_cmd_developer.c:
trace/mercury_trace_cmd_exp.c:
trace/mercury_trace_cmd_misc.c:
trace/mercury_trace_declarative.c:
trace/mercury_trace_external.c:
trace/mercury_trace_internal.c:
Use MR_strerror.
compiler/notes/coding_standards.html:
Update coding standard.
extras/net/sockets.m:
extras/net/tcp.m:
Use MR_strerror.
NEWS:
Announce change.
lex_demo.m wasn't compiling because io.print_line doesn't exist. I also
found that drawing the "> " prompt wasn't working as expected. This patch
fixes both these issues.
extras/lex/samples/lex_demo.m:
As above.
/[a-z]{10}/ in this way: `Regex = range('a', 'z') * 10'.
extras/lex/lex.m:
Removed unused and unsafe str_foldr function,
added (T * int) = regexp function.
extras/lex/samples/lex_demo.m:
Removed whitespace in comments,
added an input prompt,
added a lexeme for '//' C++ comments using the new '*' operator.
boehm_gc/.gitignore:
Ignore .obj files
extras/xml/xml.dtd.m:
extras/xml/xml.parse.m:
Change the name of functor ('1') in the multiplicity/0 type
to one. The former name does not (yet) work with the C# grade.
samples/.gitignore:
Ignore library output and sample executables.
samples/c_interface/standalone_c/.gitignore:
Ignore mercury_lib_int output files.
samples/c_interface/standalone_c/Makefile:
chmod 0644.
samples/c_interface/.gitignore:
Ignore object files and executables.
samples/java_interface/.gitignore:
Ignore Java class files and executables.
samples/lazy_list/.gitignore:
samples/muz/.gitignore:
samples/rot13/.gitignore:
Ignore executables.
samples/rot13/rot13_concise.m:
Update call to index_det to use string.det_index.
Added comments to clarify type inference.
samples/solutions/.gitignore:
Ignore executables.
samples/solutions/all_solutions.m:
samples/solutions/n_solutions.m:
samples/solutions/one_solution.m:
samples/solutions/some_solutions.m:
chmod 0644.
samples/solver_types/.gitignore:
Ignore executables.
samples/solver_types/sudoku.m:
Output the solution in a 3x3 grid.
This is a consecutive patch to my previous patch, it extends the .gitignore
files to work more thoroughly on Windows.
browser/.gitignore:
ignore .net .dll assemblies
compiler/.gitignore:
ignore *.obj
extras/.gitignore:
Ignore the tags directory
Ignore: *.bat, *.lib,
Ignore *.dll rather than lib*.dll because the .net assemblies are not
prefixed.
extras/dynamic_linking/.gitignore:
Ignore *.out (test output files)
extras/error/.gitignore:
Ignoring unix binary for the error utility
extras/lex/tests/.gitignore:
Ignore the test_regex binary
extras/moose/tests/.gitignore:
Ignore array_based.m because it is generated from array_based.moo
Replace all occurances of index0_det with det_index0 to make these examples
compatible with recent versions of Mercury.
extras/graphics/easyx/samples/bounce.m:
extras/graphics/mercury_allegro/examples/exspline.m:
extras/graphics/mercury_allegro/samples/demo/aster.m:
extras/graphics/mercury_allegro/samples/speed/view.m:
As above.
extras/.gitignore:
Mercury ignores the --use-{grade}-subdir dir
Mercury/** for git 1.8+ this recursively ignores all build files
ignoring *.mh and *.init files
*.err output files
lib*.{dll|so|a|dylib} ignores target compiler library output
*.jar ignores the Java grade output
*.exe for Windows executables
extras/dynamic_linking/.gitignore:
ignoring the copy of dl.m, name_mangle.m
ignoring hello lib and dl_test* executables
extras/moose/samples/.gitignore:
ignoring cgram.m small.m alpha.m expr.m which are
generated from the .moo grammar files
extras/graphics/mercury_cairo/samples/.gitignore:
ignoring *.png output and all executables
extras/**/.gitignore:
In each sample/test/example folder the linux executable/test
output is ignored
Lists of Unicode characters can be very long as there are many characters.
This change represents ranges of characters by storing only the first and
last character in each range.
extras/lex/lex.m:
As above.
The NFA is now using the sparse_bitset to compile the state transitions.
This significantly reduces the compile time for the regular expression, thus
enabling the use of a much larger Unicode range for character recognition.
The helper function anybut/1 has been made aware of unicode, i.e.
anybut/1 now recognises [`0x1` .. `0xffff`] - [but chars].
In addition, the regexp(string) instance now accepts Unicode chars,
the previous code was only valid for ASCII chars (when using the UTF-8
encoded C-strings in the C-based grades)
extras/lex/lex.convert_NFA_to_DFA.m:
Use the sparse_bitset ADT to build the tables used by the library.
extras/lex/lex.m:
Add a new constructor to the regexp type allowing regexps to be build
directly from character sets.
extras/lex/lex.regexp.m:
Build regexps from character sets.
extras/lex/samples/lex_demo.m:
Demonstrate the use of wide characters in the lexer demo.
extras/lex/lex.automata.m:
extras/lex/lex.lexeme.m:
Conform to above changes.
In lex.lexeme, all char codepoints where downcast to 8bit, thus rendering
Unicode matching impossible. This change removes this limitation.
extras/lex/lex.lexeme.m:
As above.
extras/lex/lex.m:
Document some caveats with the charset functions.
Add a range check to the two-argument charset function.
Simplify the anybut function.
+ Add a charset type that can be used to represent sets of characters.
These are useful when constructing lexers.
+ Start adding support for wider character sets.
+ Add support for matching on ranges of characters.
extras/lex/lex.m:
As above.
anybut/1 now uses unicode as a basis.
extras/lex/samples/lex_demo.m:
Demonstrate the new features.
extras/trailed_update/samples/vqueens.m:
Use higher-order any insts to avoid the mode error in this module.
extras/trailed_update/var.m:
Add extras modes to the freeze predicates that take closures with inst
any. (XXX This module could do with a re-write since Mercury now
implements many of the features that had to be hacked around when
it was written.)
extras/trailed_update/tr_store.m:
Conform to runtime changes.
extras/gator/genotype.m:
extras/gator/phenotype.m:
extras/graphics/samples/maze/maze.m:
extras/trailed_update/samples/interpreter.m:
Conform to standard library changes.
Add the MR_ prefix to list_empty and list_tail calls.
extras/graphics/mercury_tcltk/mtcltk.m:
In line 157, the MR_ prefix was missing from the list_empty and
list_tail calls.
Add a module that provides Mercury-level access to the function trail to the
extras distribution. This module was originally written by Mark Brown as part
of the G12 platform's common library. This verison has been lightly modified
to remove some G12-specific stuff.
extras/trail/trail.m:
Add the new new module.
extras/trail/mercury_trail.m:
Wrapper module to ensure that we get the correct library name.
extras/trail/Mercury.options:
Only install this library in C grades that support trailing.
NEWS:
Announce the addition.
Delete the empty lazy_evaluation directory from extras.
*/.cvsignore:
Make this into .gitignore files.
(Update them where necessary.)
extra/lazy_evalution:
Delete this directory; its former contents were moved
elsewhere some time ago.
available if the GLUT implementation being used is freeglut.
Using these extensions in the absence of freeglut will cause an exception to
be thrown.
extras/graphics/mercury_glut/glut.m:
Add a predicate have_freeglut/0 for testing whether freeglut
is being used.
Fix the description of glut.quit/2 - it shuts things down
gracefully rather than simply aborting.
Provide bindings to the following freeglut extensions:
* glutMainLoopEvent
* glutLeaveMainLoop
* glutGet with GLUT_FULL_SCREEN
extras/graphics/mercury_glut/glut.model.m:
Provide bindings to the following freeglut extensions:
* glutWireRhombicDodecahedron
* glutSolidRhombicDodecahedron
extras/graphics/mercury_glut/glut.window.m:
Provide bindings to the following freeglut extennsions:
* glutFullScreenToggle
* glutLeaveFullScreeen
(The latter doesn't appear to be available in the versions
of freeglut that are on the Linux machines I tested this on,
I've commented it out for the time being.)
extras/graphics/mercury_glut/*.m:
Use don't-care variables for handling the I/O state in
foreign_procs. This avoids warnings from MSVC.
extras/graphics/mercury_glut/README:
Mention that some of the freeglut extensions are now optionally
supported.
Announce the binding.
extras/graphics/mercury_glfw/glfw.m:
Address a review comment from Ian: remove equivalent buttons
from the mouse_button/0 type.
NEWS:
Announce the GLFW binding.
extras/graphics/mercury_glfw/GLFW.options:
Provide flags for linking on Linux.
extras/graphics/mercury_glfw/README:
Address review comments from Ian.
extras/README:
Add GLFW to the list of graphics libraries.
Reformat aforementioned list.
For post-commit review by Ian.
Add a Mercury binding to GLFW to the Mercury extras.
(GLFW is a lightweight library creating and managing an OpenGL rendering
context, as well as handling keyboard and mouse input. It fulfills pretty much
the same role as GLUT but has a more sane design.)
extras/graphics/mercury_glfw/mercury_glfw.m:
extras/graphics/mercury_glfw/glfw.m:
Add a Mercury binding to GLFW.
extras/graphics/mercury_glfw/README:
Document how to build and install the binding.
Provide a brief overview of the binding.
extras/graphics/mercury_glfw/GLFW.options:
extras/graphics/mercury_glfw/Mercury.options:
Mercury compiler flags for building the binding --
currently set up for Mac OS X.
extras/graphics/mercury_glfw/samples/gears.m:
extras/graphics/mercury_glfw/samples/listmodes.m:
extras/graphics/mercury_glfw/samples/triangle.m:
Add Mercury versions of some of the GLFW examples.
extra/graphics/README:
Add mercury_glfw.
Branches: main, 11.07
Fix extras/logged_output: it was suffering from some bit rot and wouldn't have
worked correctly in any case since it makes use of C variable length argument
lists in an undefined manner.
extras/logged_output/logged_output.m:
Replace a call to an out-of-date form of the MR_incr_hp macro.
In the definition of the the function ME_logged_output_vprintf,
make a copy of the varags state variable before the first call
to vprintf. This fix is _NOT_ portable, the right thing to do
would be to use C99's va_copy macro, but if there currently
appear to be some problems with the Mercury runtime headers
when GCC is used in C99 (or GNU99) mode.
Syntax and formatting updates.
extras/logged_output/main.m:
Syntax and formatting updates.
Branches: main
Remove deprecated modules and (most) deprecated procedures from the standard
library. (The remaining deprecated procedures probably need to stick around
for at least another release in order to give people time to adapt their code.)
library/dir.m:
library/list.m:
library/stack.m:
library/string.m:
library/type_desc.m:
Delete obsolete procedures.
library/svarray.m:
library/svbag.m:
library/svbimap.m:
library/sveqvclass.m:
library/svmap.m:
library/svmulti_map.m:
library/svqueue.m:
library/svset.m:
library/svvarset.m:
Delete these modules, they are no longer required since the
original predicates now have their arguments in the state-variable
friendly order.
library/library.m:
Delete the above modules.
compiler/frameopt.m:
compiler/par_loop_control.m:
compiler/rbmm.region_transformation.m:
browser/browser_test.m:
extras/windows_installer_generator/wix_gui.m:
samples/ultra_sub.m:
tests/hard_coded/rnd.m:
tests/hard_coded/type_spec_ho_term.m:
tests/hard_coded/xmlable_test.m:
Conform to the above changes.
Branches: main, 11.07
Make compilation of extras/references more reliable.
extras/references/Makefile:
extras/references/Mmakefile:
extras/references/Mercury.options:
Use mmc --make to build and install this library (as we do with
some of the other extras packages) instead of mmake. This allows
us to sue the grade filtering mechanism in mmc --make to ensure
that we only install the library in grades that support trailing.
Fix a number of problems that prevent this library installing cleanly:
+ don't require the presence of asm_fast grades; build the library in
the default grade with the trail segment component added.
+ use trail segment grades instead of fixed sized trail grades (the latter
are not installed anymore unless specifically requested by the user).
+ install the C header file that is part of this library.
+ delete ancient workarounds for supporting shared libraries on Linux.
extras/references/tests/Mmakefile:
extras/references/samples/Mmakefile:
Conform to the above changes.
Don't assume that the extension for static libraries is .a; it's
not on some systems.
extras/references/global.m:
Add a feature set pragma specifying that trailing is required.
extras/references/nb_reference.m:
s/__/./
extras/lex/lex.m:
Unrelated change: avoid using an obsolete function.
Branches: 11.07, main
Fix problems that prevent the sockets library in the extras distribution
compiling when using MSVC as the C compiler.
extras/net/sockets.mr
Fix bitrot: socketets.init/2 referred to a variable that does
not exist. (Presumably, it was deleted with the initialise
directive was added to this module.)
extras/net/tcp.m:
Include the header file that defines the type off_t.
SIGPIPE does not exist on Windows so protect any uses of
it inside #ifdefs. (Execution will abort if calls are made
to {ignore,unignore}_sigpipe on Windows.)
Branches: 11.07, main
Fix some problems in the TCP binding.
extras/net/tcp.m:
Conform the recent removal of MR_update_io from the standard library.
Use don't-care variables for the I/O state in all foreign procs.
Avoid a warning from gcc concerning mismatched signedness due
to difference betweeen the Windows and POSIX versions of the
accept function.
extras/lazy_evaluation/*:
Removed old code.
samples/lazy_list/README:
samples/lazy_list/lazy_list.m:
samples/lazy_list/lazy_list_test.m:
Code copied from old location.
lazy_list.m has been modified to ensure that it works with the current
version of library/lazy.m
extras/README:
Removed old description of lazy_evaluation
samples/README:
Describe the exitance of samples/lazy_list
Index: extras/README
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/README,v
retrieving revision 1.29
diff -u -p -b -r1.29 README
--- extras/README 2 Aug 2011 07:55:09 -0000 1.29
+++ extras/README 29 Aug 2011 06:06:42 -0000
@@ -36,11 +36,6 @@ graphics Some packages for doing graphic
GLUT, a simplified binding to Xlib, a binding
to Allegro/AllegroGL and a Mercury binding to Cairo.
-lazy_evaluation
- Some examples of the use of the standard library's
- `lazy' module, including a module `lazy_list' that defines
- a lazy list data type.
-
lex A lexer package for Mercury that works over the I/O state,
strings, and so forth. It comes with a rich set of
standard regular expressions and the user is free to add
Index: extras/lazy_evaluation/Mmakefile
===================================================================
RCS file: extras/lazy_evaluation/Mmakefile
diff -N extras/lazy_evaluation/Mmakefile
--- extras/lazy_evaluation/Mmakefile 16 Jan 2003 10:44:17 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,11 +0,0 @@
-#-----------------------------------------------------------------------------#
-# Copyright (C) 2002-2003 The University of Melbourne.
-# This file may only be copied under the terms of the GNU Library General
-# Public License - see the file COPYING.LIB in the Mercury distribution.
-#-----------------------------------------------------------------------------#
-INSTALL_PREFIX := $(INSTALL_PREFIX)/extras
--include ../Mmake.params
-default_target: all
-depend: lazy_list.depend lazy_list_test.depend
-all: liblazy_list lazy_list_test
-install: liblazy_list.install
Index: extras/lazy_evaluation/README
===================================================================
RCS file: extras/lazy_evaluation/README
diff -N extras/lazy_evaluation/README
--- extras/lazy_evaluation/README 7 Oct 2010 05:03:12 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,73 +0,0 @@
-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_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.
-
-Mercury's standard library contains.
-
- lazy.m:
- This module defines the lazy(T) type, and the force/1
- and delay/1 functions.
-
-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.
Index: extras/lazy_evaluation/lazy_list.m
===================================================================
RCS file: extras/lazy_evaluation/lazy_list.m
diff -N extras/lazy_evaluation/lazy_list.m
--- extras/lazy_evaluation/lazy_list.m 5 Aug 2010 06:55:43 -0000 1.4
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,137 +0,0 @@
-%-----------------------------------------------------------------------------%
-% vim: ts=4 sw=4 et ft=mercury
-%-----------------------------------------------------------------------------%
-%
-% This is an example of how to use the `lazy' module to define
-% a recursive lazy data type, in this case lazy lists.
-% It also defines a small number of functions and predicates
-% that operate on lazy lists.
-%
-% See also lazy_list_test.m, which is an example program using this module.
-%
-% This source file is hereby placed in the public domain. -fjh (the author).
-
-:- module lazy_list.
-:- interface.
-:- import_module lazy, int, list.
-
-%-----------------------------------------------------------------------------%
-
- % The definition of the type `lazy_list(T)':
- % A lazy lazy_list is either an empty lazy_list, denoted `[]',
- % or an element `Head' of type `T' followed by a lazily
- % evaluated tail `Tail', of type `lazy(lazy_list(T))',
- % denoted `[Head | Tail]'.
-
-:- type lazy_list(T) ---> [] ; [T | lazy(lazy_list(T))].
-
-:- inst lazy_list(I) ---> [] ; [I | lazy(lazy_list(I))].
-:- inst lazy_list == lazy_list(ground).
-
-:- inst nonempty_lazy_list(I) ---> [I | lazy(lazy_list(I))].
-:- inst nonempty_lazy_list == nonempty_lazy_list(ground).
-
-%-----------------------------------------------------------------------------%
-
- % force evaluation of (the top level of) a lazy list
-:- func force_list(lazy(lazy_list(T))) = lazy_list(T).
-:- mode force_list(in(lazy(lazy_list))) = out(lazy_list) is det.
-
-%-----------------------------------------------------------------------------%
-
- % Convert a lazy_list to an ordinary list.
-:- func to_list(lazy_list(T)) = list(T).
-:- mode to_list(in(lazy_list)) = out is det.
-
- % Convert an ordinary list to a lazy_list.
-:- func from_list(list(T)) = lazy_list(T).
-:- mode from_list(in) = out(lazy_list) is det.
-
-%-----------------------------------------------------------------------------%
-
- % A lazy_list function version of the usual append predicate:
- % append(Start, End) = List is true iff
- % `List' is the result of concatenating `Start' and `End'.
- %
-:- func append(lazy_list(T), lazy(lazy_list(T))) = lazy_list(T).
-:- mode append(in(lazy_list), in(lazy(lazy_list))) = out(lazy_list)
- is det.
-
- % member(Elem, List) :
- % True iff `List' contains `Elem'.
-:- pred member(T, lazy_list(T)).
-:- mode member(in, in(lazy_list)) is semidet.
-:- mode member(out, in(nonempty_lazy_list)) is multi.
-:- mode member(out, in(lazy_list)) is nondet.
-
-%-----------------------------------------------------------------------------%
-
- % iterate(F, X0) = [X0, F(X0), F(F(X0)), F(F(F(X0))), ...]
-:- func iterate(func(T) = T, T) = lazy_list(T).
-:- mode iterate(func(in) = out is det, in) = out(lazy_list) is det.
-
- % take(N, L) returns the first N elements of L
-:- func take(int, lazy_list(T)) = lazy_list(T).
-:- mode take(in, in(lazy_list)) = out(lazy_list) is det.
-
- % map(F, [X0, X1, X2, ...]) = [F(X0), F(X1), F(X2), ...].
-:- func map(func(X) = Y, lazy_list(X)) = lazy_list(Y).
-:- mode map(func(in) = out is det, in(lazy_list)) = out(lazy_list) is det.
-
-%-----------------------------------------------------------------------------%
-%-----------------------------------------------------------------------------%
-
-:- implementation.
-
-force_list(Xs) = list_inst_cast(force(Xs)).
-
-% Because the Mercury mode system is not properly polymorphic,
-% it doesn't always infer the right inst. We sometimes need
-% to use inst casts (which can be implemented using `pragma foreign_proc').
-% :-(
-
-:- func list_inst_cast(lazy_list(T)) = lazy_list(T).
-:- mode list_inst_cast(in) = out(lazy_list) is det.
-
-:- pragma foreign_proc("C",
- list_inst_cast(F::in) = (F2::out(lazy_list)),
- [promise_pure, will_not_call_mercury, thread_safe],
-"
- F2 = F;
-").
-
-%-----------------------------------------------------------------------------%
-
-to_list([]) = [].
-to_list([X | Xs]) = [X | to_list(force_list(Xs))].
-
-from_list([]) = [].
-from_list([X | Xs]) =
- [X | delay((func) = R :- R = from_list(Xs))].
-
-%-----------------------------------------------------------------------------%
-
-append([], Ys) = force_list(Ys).
-append([X | Xs], Ys) =
- [X | delay((func) = R :- R = append(force_list(Xs), Ys))].
-
-member(X, [X | _]).
-member(X, [_ | Xs]) :-
- member(X, force_list(Xs)).
-
-%-----------------------------------------------------------------------------%
-
-map(_, []) = [].
-map(F, [H|T]) = [F(H) | delay((func) = R :- R = map(F, force_list(T)))].
-
-iterate(F, X0) = [X0 | delay((func) = R :- R = iterate(F, F(X0)))].
-
-take(_, []) = [].
-take(N, [X|Xs]) =
- (if N > 0 then
- [X | delay((func) = R :- R = take(N-1, force_list(Xs)))]
- else
- []
- ).
-
-%-----------------------------------------------------------------------------%
Index: extras/lazy_evaluation/lazy_list_test.m
===================================================================
RCS file: extras/lazy_evaluation/lazy_list_test.m
diff -N extras/lazy_evaluation/lazy_list_test.m
--- extras/lazy_evaluation/lazy_list_test.m 15 Mar 1999 08:56:59 -0000 1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,27 +0,0 @@
-%-----------------------------------------------------------------------------%
-%
-% lazy_list_test.m:
-% This is a trivial example of the use of lazy lists.
-%
-% This source file is hereby placed in the public domain. -fjh (the author).
-
-:- module lazy_list_test.
-:- interface.
-:- import_module io.
-
-:- pred main(io__state::di, io__state::uo) is det.
-
-%-----------------------------------------------------------------------------%
-
-:- implementation.
-:- import_module lazy, lazy_list, int.
-
-:- func double(int) = int.
-double(X) = 2 * X.
-
-main -->
- { L = iterate(double, 1) }, % construct an infinite list...
- { L10 = take(10, L) }, % extract the first 10 elements
- print(to_list(L10)), nl. % print them
-
-%-----------------------------------------------------------------------------%
Index: samples/README
===================================================================
RCS file: /home/mercury1/repository/mercury/samples/README,v
retrieving revision 1.13
diff -u -p -b -r1.13 README
--- samples/README 8 Jul 2011 04:08:27 -0000 1.13
+++ samples/README 29 Aug 2011 05:47:53 -0000
@@ -72,3 +72,8 @@ muz This directory contains a syntax c
solver_types This directory contains an example solver type
implementation and some sample applications.
+
+lazy_list This directory contains an example of the lazy module
+ can be used to implement lazy data structures, in this
+ case a lazy list.
+
Index: samples/lazy_list/README
===================================================================
RCS file: samples/lazy_list/README
diff -N samples/lazy_list/README
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ samples/lazy_list/README 29 Aug 2011 05:56:20 -0000
@@ -0,0 +1,69 @@
+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_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.
+
+Mercury's standard library contains.
+
+ lazy.m:
+ This module defines the lazy(T) type, and the force/1
+ and delay/1 functions.
+
+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. This is
+because the lazy(T) type currently uses two levels of indirection, whereas it
+could be implemented with only one.
+
Index: samples/lazy_list/lazy_list.m
===================================================================
RCS file: samples/lazy_list/lazy_list.m
diff -N samples/lazy_list/lazy_list.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ samples/lazy_list/lazy_list.m 29 Aug 2011 05:44:52 -0000
@@ -0,0 +1,111 @@
+%-----------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%-----------------------------------------------------------------------------%
+%
+% This is an example of how to use the `lazy' module to define
+% a recursive lazy data type, in this case lazy lists.
+% It also defines a small number of functions and predicates
+% that operate on lazy lists.
+%
+% See also lazy_list_test.m, which is an example program using this module.
+%
+% This source file is hereby placed in the public domain. -fjh (the author).
+% Modified by Paul Bone (2011) for compatibilty with the lazy module in
+% Mercury's standard library.
+
+:- module lazy_list.
+:- interface.
+:- import_module lazy, int, list.
+
+%-----------------------------------------------------------------------------%
+
+ % The definition of the type `lazy_list(T)':
+ % A lazy lazy_list is either an empty lazy_list, denoted `[]',
+ % or an element `Head' of type `T' followed by a lazily
+ % evaluated tail `Tail', of type `lazy(lazy_list(T))',
+ % denoted `[Head | Tail]'.
+
+:- type lazy_list(T) ---> [] ; [T | lazy(lazy_list(T))].
+
+%-----------------------------------------------------------------------------%
+
+ % force evaluation of (the top level of) a lazy list
+:- func force_list(lazy(lazy_list(T))) = lazy_list(T).
+
+%-----------------------------------------------------------------------------%
+
+ % Convert a lazy_list to an ordinary list.
+:- func to_list(lazy_list(T)) = list(T).
+
+ % Convert an ordinary list to a lazy_list.
+:- func from_list(list(T)) = lazy_list(T).
+
+%-----------------------------------------------------------------------------%
+
+ % A lazy_list function version of the usual append predicate:
+ % append(Start, End) = List is true iff
+ % `List' is the result of concatenating `Start' and `End'.
+ %
+:- func append(lazy_list(T), lazy(lazy_list(T))) = lazy_list(T).
+
+ % member(Elem, List) :
+ % True iff `List' contains `Elem'.
+:- pred member(T, lazy_list(T)).
+:- mode member(in, in) is semidet.
+:- mode member(out, in) is nondet.
+
+%-----------------------------------------------------------------------------%
+
+ % iterate(F, X0) = [X0, F(X0), F(F(X0)), F(F(F(X0))), ...]
+:- func iterate(func(T) = T, T) = lazy_list(T).
+:- mode iterate(func(in) = out is det, in) = out is det.
+
+ % take(N, L) returns the first N elements of L
+:- func take(int, lazy_list(T)) = lazy_list(T).
+
+ % map(F, [X0, X1, X2, ...]) = [F(X0), F(X1), F(X2), ...].
+:- func map(func(X) = Y, lazy_list(X)) = lazy_list(Y).
+:- mode map(func(in) = out is det, in) = out is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+force_list(Xs) = force(Xs).
+
+%-----------------------------------------------------------------------------%
+
+to_list([]) = [].
+to_list([X | Xs]) = [X | to_list(force_list(Xs))].
+
+from_list([]) = [].
+from_list([X | Xs]) =
+ [X | val(from_list(Xs))].
+
+%-----------------------------------------------------------------------------%
+
+append([], Ys) = force_list(Ys).
+append([X | Xs], Ys) =
+ [X | delay((func) = R :- R = append(force_list(Xs), Ys))].
+
+member(X, [X | _]).
+member(X, [_ | Xs]) :-
+ member(X, force_list(Xs)).
+
+%-----------------------------------------------------------------------------%
+
+map(_, []) = [].
+map(F, [H|T]) = [F(H) | delay((func) = R :- R = map(F, force_list(T)))].
+
+iterate(F, X0) = [X0 | delay((func) = R :- R = iterate(F, F(X0)))].
+
+take(_, []) = [].
+take(N, [X|Xs]) =
+ (if N > 0 then
+ [X | delay((func) = R :- R = take(N-1, force_list(Xs)))]
+ else
+ []
+ ).
+
+%-----------------------------------------------------------------------------%
Index: samples/lazy_list/lazy_list_test.m
===================================================================
RCS file: samples/lazy_list/lazy_list_test.m
diff -N samples/lazy_list/lazy_list_test.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ samples/lazy_list/lazy_list_test.m 29 Aug 2011 05:35:08 -0000
@@ -0,0 +1,27 @@
+%-----------------------------------------------------------------------------%
+%
+% lazy_list_test.m:
+% This is a trivial example of the use of lazy lists.
+%
+% This source file is hereby placed in the public domain. -fjh (the author).
+
+:- module lazy_list_test.
+:- interface.
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+:- import_module lazy, lazy_list, int.
+
+:- func double(int) = int.
+double(X) = 2 * X.
+
+main -->
+ { L = iterate(double, 1) }, % construct an infinite list...
+ { L10 = take(10, L) }, % extract the first 10 elements
+ print(to_list(L10)), nl. % print them
+
+%-----------------------------------------------------------------------------%
Branches: main, 11.07
Fix top-level invocations of mmake in the extras distribution. They were
breaking because the lex subdirectory didn't have an Mmakefile. (It uses
mmc --make and a normal Makefile instead.)
Make more of the extras distribution build from the top-level.
extras/lex/Mmakefile:
Add an Mmakefile that contains the targets required by the top-level
extras distribution Mmakefile. Each of the targets just forwards
the work to the actual Makefile.
extras/Mmakefile:
Update the list of things that won't compile ``out-of-the-box''.
(XXX we should use autoconf to configure these.)
Build the base64 encoding library, the fixed point arithmetic library
and the error utility by default.
extras/README:
Update the description of the lazy_evaluation subdirectory.
extras/base64/Makefile:
extras/base64/Mmakefile:
extras/base64/mercury_base64.m:
extars/base64/Mercury.options:
Build and install base64 as a library. We use mmc --make, controlled
from a normal Makefile to do this and then put a forwarding Mmakefile
in place using so that compilation from the top-level of the extras
distribution works. (One reason for doing this is that mmc --make
provides grade filtering capabilities which are needed here since
this library will only work in C grades.)
extras/base64/base64.m:
Avoid a compilation error: sizeof cannot be used on things with
an incomplete type.
extras/fixed/Makefile:
extras/fixed/Mmakefile:
extras/fixed/Mercury.options:
extras/fixed/mercury_fixed.m:
Build and install fixed as a library. As with base64, use mmc --make
and add a forwarding Mmakefile.
extras/fixed/fixed.m:
Style and formatting fixes.
extras/lex/Makefile:
Add a realclean target
extras/lex/lex.lexeme.m:
Replace a call to a deprecated procedure.