172 lines
6.2 KiB
Plaintext
172 lines
6.2 KiB
Plaintext
_Lazy Scheme_
|
|
-------------
|
|
|
|
[This documentation begins with a description of the lazy language,
|
|
and later on provides a description of all modules. Specifically, the
|
|
"promise.ss" module (together with the "force.ss" module) can be used
|
|
as a better alternative to MzScheme's promises.]
|
|
|
|
Lazy Scheme is available as both a language level and a module that
|
|
can be used to write lazy code. To write lazy code, simply use
|
|
"lazy.ss" as your module's language:
|
|
|
|
(module foo (lib "lazy.ss" "lazy")
|
|
...lazy code here...)
|
|
|
|
Function applications are delayed, and promises are automatically
|
|
forced. The language provides bindings that are equivalent to most of
|
|
MzScheme and the list library. Primitives are strict in the expected
|
|
places; struct constructors are lazy; `if', `and', `or' etc are plain
|
|
(lazy) functions. Strict functionality is provided as is: begin, I/O,
|
|
mutation, parameterization, etc. To have your code make sense, you
|
|
should chain side effects in `begin's which will sequence things
|
|
properly. (Note: this is similar to threading monads through your
|
|
code -- only use `begin' where order matters.)
|
|
|
|
Mixing lazy and strict code is simple: you just write the lazy code in
|
|
the lazy language, and strict code as usual. The lazy language treats
|
|
imported functions (those that were not defined in the lazy language)
|
|
as strict, and on the strict side you only need to force (possibly
|
|
recursively) through promises.
|
|
|
|
There are a few additional bindings, the important ones are special
|
|
forms that force strict behavior -- there are severals of these that
|
|
are useful in forcing different parts of a value in different ways:
|
|
|
|
> (! expr)
|
|
evaluates `expr' strictly (the result is always forced (over and
|
|
over until it gets a non-promise value)).
|
|
|
|
> (!! expr)
|
|
similar to `!', but recursively forces a structure (eg, lists).
|
|
|
|
> (!!! expr)
|
|
similar to `!!', but also wraps procedures that it finds so their
|
|
outputs are forced (so they are usable in a astrict world).
|
|
|
|
> (!list expr)
|
|
forces the `expr' which is expected to be a list, and forces the
|
|
cdrs recursively to expose a proper list structure.
|
|
|
|
> (!!list expr)
|
|
similar to `!list', but also forces (using `!') the elements of the
|
|
list.
|
|
|
|
There are a few side-effect bindings that are provided as is. For
|
|
example, `read' and `printf' do the obvious thing -- but note that the
|
|
language is a call-by-need, and you need to be aware when promises are
|
|
forced. There are also bindings for `begin' (delays a computation
|
|
that forces all sub-expressions), `when', `unless', etc. These are,
|
|
however, less reliable and might change (or be dropped) in the future.
|
|
|
|
* Multiple values
|
|
|
|
To avoid dealing with multiple values, they are treated as a single
|
|
tuple in the lazy language. This is implemented as a
|
|
`multiple-values' struct, with a `values' slot.
|
|
|
|
> split-values
|
|
is used to split such a tuple to actual multiple values. (This may
|
|
change in the future.)
|
|
|
|
> (!values expr)
|
|
forces `expr', and uses `split-values' on the result.
|
|
|
|
> (!!values expr)
|
|
similar to `!values', but forces each of the values (not
|
|
recursively).
|
|
|
|
|
|
_mz-without-promises.ss_
|
|
------------------------
|
|
|
|
This is a tiny module that provides all of `mzscheme', except for
|
|
promise-related functionality (`delay', `force', `promise?'). This is
|
|
because "promise.ss" defines and provides the same names. It is
|
|
intended as a helper, but you can use it together with "promise.ss" to
|
|
get a mzscheme-like language where promises are implemented by
|
|
"promise.ss".
|
|
|
|
|
|
_promise.ss_
|
|
------------
|
|
|
|
This module implements lazy promises. It provides the following four
|
|
bindings:
|
|
|
|
> (delay expr) [syntax]
|
|
|
|
Similar in functionality to Scheme's `delay'.
|
|
|
|
> (lazy expr) [syntax]
|
|
|
|
Creates a `lazy' promise. See below for details.
|
|
|
|
> (force x) [procedure]
|
|
|
|
Force a promise that was generated by `delay' or `lazy'. Similar to
|
|
Scheme's `force', except that non-promise values are simply returned.
|
|
|
|
> (promise? x) [procedure]
|
|
|
|
A predicate for promise values.
|
|
|
|
Note: this module implements a *new* kind of promises. MzScheme
|
|
promises are therefore treated as other values -- which means that
|
|
they are not forced by this module's `force'.
|
|
|
|
Generally speaking, if you use only `delay', `force', and `promise?',
|
|
you get the same functionality as in Scheme. See below for two
|
|
(relatively minor) differences.
|
|
|
|
`lazy' implements a new kind of promise. When used with expressions,
|
|
it behaves like `delay'. However, when `lazy' is used with an
|
|
expression that already evaluates to a promise, it combines with it
|
|
such that `force' will go through both promises. In other words,
|
|
`(lazy X)' is equivalent to `(lazy (lazy X))'. The main feature of
|
|
this implementation of promises is that `lazy' is safe-for-space (see
|
|
srfi-45 for details) -- this is crucial for tail-recursion in Lazy
|
|
Scheme.
|
|
|
|
To summarize, a sequence of `lazy's is forced with a single use of
|
|
`force', and each additional `delay' requires an additional `force' --
|
|
for example,
|
|
|
|
(lazy^i (delay (lazy^j (delay (lazy^k E)))))
|
|
|
|
requires three `force's to evaluate E.
|
|
|
|
Note: `lazy' cannot be used with an expression that evaluates to
|
|
multiple values. `delay' is, however, is fine with multiple values.
|
|
(This is for efficiency in the lazy language, where multiple values
|
|
are avoided.)
|
|
|
|
As mentioned above, using `delay' and `force' is as in Scheme, except
|
|
for two differences. The first is a technicality -- force is an
|
|
identity for non-promise values. This makes it more convenient in
|
|
implementing the lazy language, where there is no difference between a
|
|
values and a promises.
|
|
|
|
The second difference is that circular (re-entrant) promises are not
|
|
permitted (i.e., when a promise is being forced, trying to force it in
|
|
the process will raise an error). For example, the following code
|
|
(see srfi-45 for additional examples):
|
|
|
|
(let ([count 5])
|
|
(define p (delay (if (<= count 0)
|
|
count
|
|
(begin (set! count (- count 1)) (force p)))))
|
|
(force p))
|
|
|
|
returns 0 with Scheme's `delay'/`force', but aborts with an error with
|
|
this module's promises. This restriction leads to faster code (see
|
|
http://srfi.schemers.org/srfi-45/post-mail-archive/msg00011.html for
|
|
some additional details), while preventing diverging code (the only
|
|
reasonable way to use circular promises is using mutation as above).
|
|
|
|
|
|
_force.ss_
|
|
----------
|
|
|
|
[TODO]
|