[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] SRFI-45: Support delayed expressions that return multiple va
From: |
Mark H Weaver |
Subject: |
Re: [PATCH] SRFI-45: Support delayed expressions that return multiple values |
Date: |
Mon, 18 Mar 2013 21:53:21 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) |
Here's an improved patch that updates the manual and adds tests.
Mark
>From 220fb56249b462ad1b205a45a4953e6dc857c96e Mon Sep 17 00:00:00 2001
From: Mark H Weaver <address@hidden>
Date: Mon, 18 Mar 2013 20:01:12 -0400
Subject: [PATCH] SRFI-45: Support delayed expressions that return multiple
values.
* module/srfi/srfi-45.scm (eager): Accept any number of arguments.
Store the list of arguments in the value record. Previously, only one
argument was accepted, and that value was stored in the value record.
(delay): Support expressions that return any number of arguments.
(force): Return the list of values stored in the value record.
* doc/ref/srfi-modules.texi (SRFI-45): Update docs. Remove typing
for simplicity in discussing multiple values.
* test-suite/tests/srfi-45.test: Add tests.
---
doc/ref/srfi-modules.texi | 53 ++++++++++++++++++++++++-----------------
module/srfi/srfi-45.scm | 16 +++++++------
test-suite/tests/srfi-45.test | 34 ++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 29 deletions(-)
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index af1afc0..099f27e 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -3833,45 +3833,54 @@ words, no program that uses the R5RS definitions of
delay and force will
break if those definition are replaced by the SRFI-45 definitions of
delay and force.
+Guile compatibly extends SRFI-45 to support multiple values.
+
@deffn {Scheme Syntax} delay expression
-Takes an expression of arbitrary type @var{a} and returns a promise of
-type @code{(Promise @var{a})} which at some point in the future may be
-asked (by the @code{force} procedure) to evaluate the expression and
-deliver the resulting value.
+Takes an expression and returns a promise which at some point in the
+future may be asked (by the @code{force} procedure) to evaluate the
+expression and deliver the resulting value(s).
@end deffn
@deffn {Scheme Syntax} lazy expression
-Takes an expression of type @code{(Promise @var{a})} and returns a
-promise of type @code{(Promise @var{a})} which at some point in the
-future may be asked (by the @code{force} procedure) to evaluate the
-expression and deliver the resulting promise.
+Takes an expression (which must evaluate to a promise) and returns a
+promise which at some point in the future may be asked (by the
address@hidden procedure) to evaluate the expression and deliver the
+resulting promise.
@end deffn
address@hidden {Scheme Procedure} force expression
-Takes an argument of type @code{(Promise @var{a})} and returns a value
-of type @var{a} as follows: If a value of type @var{a} has been computed
-for the promise, this value is returned. Otherwise, the promise is
-first evaluated, then overwritten by the obtained promise or value, and
-then force is again applied (iteratively) to the promise.
address@hidden {Scheme Procedure} force promise
+Takes a promise and returns the associated value(s) as follows: If
+value(s) have been computed for the promise, these value(s) are
+returned. Otherwise, the promise is first evaluated, then overwritten
+by the obtained promise or value(s), and then force is again applied
+(iteratively) to the promise.
@end deffn
address@hidden {Scheme Procedure} eager expression
-Takes an argument of type @var{a} and returns a value of type
address@hidden(Promise @var{a})}. As opposed to @code{delay}, the argument is
-evaluated eagerly. Semantically, writing @code{(eager expression)} is
-equivalent to writing
address@hidden {Scheme Procedure} eager value ...
+Takes any number of argument(s) and returns a promise. As opposed to
address@hidden, the argument(s) are evaluated eagerly. Semantically,
+writing @code{(eager expression)} is equivalent to writing
@lisp
(let ((value expression)) (delay value)).
@end lisp
However, the former is more efficient since it does not require
-unnecessary creation and evaluation of thunks. We also have the
-equivalence
+unnecessary creation and evaluation of thunks. For expressions that
+return a single value, we also have the equivalence
@lisp
(delay expression) = (lazy (eager expression))
@end lisp
+
+For expressions that return arbitrary numbers of values, we have the
+equivalence
+
address@hidden
+(delay expression) = (lazy (call-with-values
+ (lambda () expression)
+ eager))
address@hidden lisp
@end deffn
The following reduction rules may be helpful for reasoning about these
@@ -3881,7 +3890,7 @@ usage semantics specified above:
@lisp
(force (delay expression)) -> expression
(force (lazy expression)) -> (force expression)
-(force (eager value)) -> value
+(force (eager value ...)) -> value ...
@end lisp
@subsubheading Correct usage
diff --git a/module/srfi/srfi-45.scm b/module/srfi/srfi-45.scm
index 29b0393..a44cc97 100644
--- a/module/srfi/srfi-45.scm
+++ b/module/srfi/srfi-45.scm
@@ -1,6 +1,6 @@
;;; srfi-45.scm -- Primitives for Expressing Iterative Lazy Algorithms
-;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2010, 2011, 2013 Free Software Foundation, Inc.
;; Copyright (C) 2003 André van Tonder. All Rights Reserved.
;; Permission is hereby granted, free of charge, to any person
@@ -25,8 +25,8 @@
;;; Commentary:
-;; This is the code of the reference implementation of SRFI-45, slightly
-;; modified to use SRFI-9.
+;; This is the code of the reference implementation of SRFI-45,
+;; modified to use SRFI-9 and to support multiple values.
;; This module is documented in the Guile Reference Manual.
@@ -50,16 +50,18 @@
(define-syntax-rule (lazy exp)
(make-promise (make-value 'lazy (lambda () exp))))
-(define (eager x)
- (make-promise (make-value 'eager x)))
+(define (eager . xs)
+ (make-promise (make-value 'eager xs)))
(define-syntax-rule (delay exp)
- (lazy (eager exp)))
+ (lazy (call-with-values
+ (lambda () exp)
+ eager)))
(define (force promise)
(let ((content (promise-val promise)))
(case (value-tag content)
- ((eager) (value-proc content))
+ ((eager) (apply values (value-proc content)))
((lazy) (let* ((promise* ((value-proc content)))
(content (promise-val promise))) ; *
(if (not (eqv? (value-tag content) 'eager)) ; *
diff --git a/test-suite/tests/srfi-45.test b/test-suite/tests/srfi-45.test
index 573eea0..d72de60 100644
--- a/test-suite/tests/srfi-45.test
+++ b/test-suite/tests/srfi-45.test
@@ -258,3 +258,37 @@
;; Commented out since it takes too long
#;
(test-equal 300000000 (force (times3 100000000))) ;==> bounded space
+
+
+;======================================================================
+; Test memoization of multiple values (non-standard extension in Guile)
+
+(with-test-prefix "Multiple values (non-standard)"
+
+ (let ((promise (delay (values 1 2 3))))
+ (pass-if-equal "Multiple values delay"
+ '(1 2 3)
+ (call-with-values
+ (lambda () (force promise))
+ list)))
+
+ (let ((promise (eager 1 2 3)))
+ (pass-if-equal "Multiple values eager"
+ '(1 2 3)
+ (call-with-values
+ (lambda () (force promise))
+ list)))
+
+ (let ((promise (delay (values))))
+ (pass-if-equal "Zero values delay"
+ '()
+ (call-with-values
+ (lambda () (force promise))
+ list)))
+
+ (let ((promise (eager)))
+ (pass-if-equal "Zero values eager"
+ '()
+ (call-with-values
+ (lambda () (force promise))
+ list))))
--
1.7.10.4