commit 86aaa15c49769f2edbf1fdf1ad9f22573cec2f88
parent ea7a15fba27ea3604d8c52e570bea78b976761c2
Author: Wolfgang Corcoran-Mathe <wcm@sigwinch.xyz>
Date: Thu, 1 Feb 2024 00:07:20 -0500
Delayed evaluation: Texify.
Diffstat:
1 file changed, 79 insertions(+), 57 deletions(-)
diff --git a/doc/r7rs-small/r7rs-small.texinfo b/doc/r7rs-small/r7rs-small.texinfo
@@ -2081,40 +2081,48 @@ invoking the procedure named by @svar{variable}.
@node Delayed evaluation
@subsection Delayed evaluation
-lazy library syntax: (delay @svar{expression})
-
-Semantics: The delay construct is used together with the procedure force to implement
-lazy evaluation or call by need. (delay @svar{expression}) returns an object called a promise which
-at some point in the future can be asked (by the force procedure) to evaluate
-@svar{expression}, and deliver the resulting value. The effect of @svar{expression} returning
-multiple values is unspecified.
-
-lazy library syntax: (delay-force @svar{expression})
-
-Semantics: The expression (delay-force
-
-expression) is conceptually similar to (delay (force
+@deffn {lazy library syntax} delay @svar{expression}
+
+The @code{delay} construct is used together with the procedure @code{force} to
+implement @dfn{lazy evaluation} or @dfn{call by need}.
+@code{(delay} @svar{expression}@code{)} returns an object called a
+@dfn{promise} which at some point in the future can be asked (by
+the @code{force} procedure) to evaluate
+@svar{expression}, and deliver the resulting value.
+The effect of @svar{expression} returning multiple values
+is unspecified.
-expression)), with the difference that forcing the result of delay-force will in effect result in
-a tail call to (force
+@end deffn
-expression), while forcing the result of (delay (force
+@deffn {lazy library syntax} delay-force @svar{expression}
-expression)) might not. Thus iterative lazy algorithms that might result in a long series of
-chains of delay and force can be rewritten using delay-force to prevent consuming
+The expression @code{(delay-force} @var{expression}@code{)} is conceptually similar to
+@code{(delay (force} @var{expression}@code{))},
+with the difference that forcing the result
+of @code{delay-force} will in effect result in a tail call to
+@code{(force} @var{expression}@code{)},
+while forcing the result of
+@code{(delay (force} @var{expression}@code{))}
+might not. Thus
+iterative lazy algorithms that might result in a long series of chains of
+@code{delay} and @code{force}
+can be rewritten using @code{delay-force} to prevent consuming
unbounded space during evaluation.
-@deffn {lazy library procedure} force promise
-
-The force procedure forces the value of a
+@end deffn
-promise created by delay, delay-force, or make-promise.If no value has been computed for
-the promise, then a value is computed and returned. The value of the promise must be
-cached (or ``memoized'') so that if it is forced a second time, the previously computed
-value is returned. Consequently, a delayed expression is evaluated using the parameter
-values and exception handler of the call to force which first requested its value. If
+@deffn {lazy library procedure} force promise
-promise is not a promise, it may be returned unchanged.
+The @code{force} procedure forces the value of a @var{promise} created
+by @code{delay}, @code{delay-force}, or @code{make-promise}.
+If no value has been computed for the promise, then a value is
+computed and returned. The value of the promise must be cached (or
+``memoized'') so that if it is forced a second time, the previously
+computed value is returned.
+Consequently, a delayed expression is evaluated using the parameter
+values and exception handler of the call to @code{force} which first
+requested its value.
+If @var{promise} is not a promise, it may be returned unchanged.
@example
(force (delay (+ 1 2))) @result{} 3
@@ -2136,12 +2144,16 @@ promise is not a promise, it may be returned unchanged.
@result{} 2
@end example
+@end deffn
+
The following example is a mechanical transformation of a lazy
-stream-filtering algorithm into Scheme. Each call to a constructor is wrapped in delay, and
-each argument passed to a deconstructor is wrapped in force. The use of (delay-force ...)
-instead of (delay (force ...)) around the body of the procedure ensures that an
-ever-growing sequence of pending promises does not exhaust available storage, because
-force will in effect force such sequences iteratively.
+stream-filtering algorithm into Scheme. Each call to a constructor is
+wrapped in @code{delay}, and each argument passed to a deconstructor is
+wrapped in @code{force}. The use of @code{(delay-force @dots{})} instead of
+@code{(delay (force @dots{}))} around the body of the procedure ensures that an
+ever-growing sequence of pending promises does not
+exhaust available storage,
+because @code{force} will in effect force such sequences iteratively.
@example
(define (stream-filter p? s)
@@ -2154,14 +2166,14 @@ force will in effect force such sequences iteratively.
(delay (cons h (stream-filter p? t)))
(stream-filter p? t))))))
-(head (tail (tail (stream-filter odd? integers))))
- @result{} 5
+(head (tail (tail (stream-filter odd? integers)))) @result{} 5
@end example
-The following examples are not intended to illustrate good
-programming style, as delay, force, and delay-force are mainly intended for programs
-written in the functional style. However, they do illustrate the property that only one value
-is computed for a promise, no matter how many times it is forced.
+The following examples are not intended to illustrate good programming
+style, as @code{delay}, @code{force}, and @code{delay-force} are mainly intended
+for programs written in the functional style.
+However, they do illustrate the property that only one value is
+computed for a promise, no matter how many times it is forced.
@example
(define count 0)
@@ -2171,39 +2183,49 @@ is computed for a promise, no matter how many times it is forced.
count
(force p)))))
(define x 5)
-p @result{} a promise
-(force p) @result{} 6
-p @result{} a promise, still
+p @result{} @r{a promise}
+(force p) @result{} 6
+p @result{} @r{a promise, still}
(begin (set! x 10)
- (force p)) @result{} 6
+ (force p)) @result{} 6
@end example
-Various extensions to this semantics of delay, force and delay-force
-are supported in some implementations:
+Various extensions to this semantics of @code{delay}, @code{force} and
+@code{delay-force} are supported in some implementations:
-* Calling force on an object that is not a promise may simply return the object.
+@itemize
+@item
+Calling @code{force} on an object that is not a promise may simply return the object.
-* It may be the case that there is no means by which a promise can be operationally
+@item
+It may be the case that there is no means by which a promise can be operationally
distinguished from its forced value. That is, expressions like the following may evaluate
- to either #t or to #f, depending on the implementation:
+ to either @code{#t} or to @code{#f}, depending on the implementation:
+
+@example
+(eqv? (delay 1) 1) @result{} @r{unspecified}
+(pair? (delay (cons 1 2))) @result{} @r{unspecified}
+@end example
- (eqv? (delay 1) 1) @result{} unspecified
- (pair? (delay (cons 1 2))) @result{} unspecified
-* Implementations may implement ``implicit forcing,'' where the value of a promise is
- forced by procedures that operate only on arguments of a certain type, like cdr and *.
- However, procedures that operate uniformly on their arguments, like list, must not
+@item
+Implementations may implement ``implicit forcing,'' where the value of a promise is
+ forced by procedures that operate only on arguments of a certain type, like
+@code{cdr} and @code{*}.
+ However, procedures that operate uniformly on their arguments, like
+@code{list}, must not
force them.
@example
-(+ (delay (* 3 7)) 13) @result{} unspecified
- (car
- (list (delay (* 3 7)) 13)) @result{} a promise
+(+ (delay (* 3 7)) 13) @result{} @r{unspecified}
+(car
+ (list (delay (* 3 7)) 13)) @result{} @r{a promise}
@end example
-@end deffn
+@end itemize
@deffn {lazy library procedure} promise? obj
-The promise? procedure returns #t if its argument is a promise, and #f otherwise. Note
+The promise? procedure returns @code{#t} if its argument is a promise, and
+@code{#f} otherwise. Note
that promises are not necessarily disjoint from other Scheme types such as procedures.
@end deffn