document the promise module
svn: r6916
This commit is contained in:
parent
1119702903
commit
3b6e85aad0
|
@ -1,23 +1,32 @@
|
|||
This collection implements _Lazy Scheme_.
|
||||
_Lazy Scheme_
|
||||
-------------
|
||||
|
||||
It is available as a language level and as a module that can be used
|
||||
to write lazy code. Code that uses the "lazy.ss" as a module
|
||||
language:
|
||||
[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...)
|
||||
|
||||
is lazy code, which is implemented using standard promises: 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.
|
||||
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 the rest as usual. The lazy language treats
|
||||
imported functions (that were not defined in the lazy language) as
|
||||
strict, and on the strict side you only need to force (possibly
|
||||
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
|
||||
|
@ -50,12 +59,10 @@ 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
|
||||
|
||||
Multiple values
|
||||
---------------
|
||||
|
||||
Also, to avoid dealing with multiple values, they are treated as a
|
||||
single tuple in the lazy language. This is implemented as a
|
||||
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
|
||||
|
@ -70,11 +77,90 @@ single tuple in the lazy language. This is implemented as a
|
|||
recursively).
|
||||
|
||||
|
||||
Making strict code interact with lazy code
|
||||
------------------------------------------
|
||||
_mz-without-promises.ss_
|
||||
------------------------
|
||||
|
||||
To make it easy for strict code to interact with lazy code, use the
|
||||
_force.ss_ module: it provides the above bindings (as functions) that
|
||||
can be used to force promises in various ways.
|
||||
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".
|
||||
|
||||
[More documentation will be added.]
|
||||
|
||||
_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.
|
||||
|
||||
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]
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
;; (define-struct promise (p)) <-- use a more sophisticated struct below
|
||||
|
||||
;; promise that can print in meaningful ways
|
||||
;; Promise records (note: print in meaningful ways like thunks)
|
||||
(define-values (promise promise? p:ref p:set!)
|
||||
(let*-values
|
||||
([(printer)
|
||||
|
@ -44,7 +44,7 @@
|
|||
;; | (promise <promise>) (shared promise)
|
||||
;; | (promise #f) (currently running)
|
||||
|
||||
;; creates a `composable' promise
|
||||
;; Creates a `composable' promise
|
||||
;; X = (force (lazy X)) = (force (lazy (lazy X))) = (force (lazy^n X))
|
||||
(define-syntax (lazy stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -53,14 +53,14 @@
|
|||
'inferred-name (syntax-local-name))])
|
||||
(syntax/loc stx (promise proc)))]))
|
||||
|
||||
;; creates a promise that does not compose
|
||||
;; Creates a promise that does not compose
|
||||
;; X = (force (delay X)) = (force (lazy (delay X)))
|
||||
;; = (force (lazy^n (delay X)))
|
||||
;; X = (force (force (delay (delay X)))) =/= (force (delay (delay X)))
|
||||
;; so each sequence of `(lazy^n o delay)^m' requires m `force's and a
|
||||
;; sequence of `(lazy^n o delay)^m o lazy^k' requires m+1 `force's (for k>0)
|
||||
;; (This is not needed with a lazy language (see the above URL for details),
|
||||
;; but provided for completeness)
|
||||
;; but provided for completeness.)
|
||||
(define-syntax (delay stx)
|
||||
(syntax-case stx ()
|
||||
[(delay expr) (syntax/loc stx (lazy (promise (list expr))))]))
|
||||
|
|
Loading…
Reference in New Issue
Block a user