*Abdulaziz Ghuloum <xxxxxx@cs.indiana.edu>
|I assume you mean "other Scheme values", not expressions. Doesn't the
|following code bind the evaluated result of VALUES to a single variable?
|
|(call-with-values (lambda () (values 1 2 3))
| (lambda VALS
| VALS))
The VALS is not the evaluated result of (values 1 2 3) but a list which the
evaluated result is converted into.
|QUOTE: Moreover, the pair of VALUES and CALL-WITH-VALUES is clumsy to use
|Is this a fact or an opinion? A SRFI would be more appealing to implementors
|if its rationale is based on facts.
If it is an inconvenient way that "decomposition of multiple values is done by
simple application", it will be not a fact.
|QUOTE: and somewhat slow under some circumstances.
|How slow is "somewhat slow"? How do you quantify it? And what are the
|circumstances that make VALUES and CALL-WITH-VALUES somewhat slow? Or
|do you really mean under some *implementations*? Was the topic of
|Efficient Implementation of Multiple Return Values in Scheme ever
|discussed in the literature?
Even in Chez Petite Scheme and Scheme48 that have VALUES/CALL-WITH-VLUES
implemented with "An Efficient Implementation of Multiple Return Values in
Scheme (http://citeseer.ist.psu.edu/27481.html)", VALUES/CALL-WITH-VALUES is
somewhat slow under some circumstances.
The following are the results of simple tests "on REPL".(Intel 586, Debian or
Windows)
(define-syntax mu
(syntax-rules ()
((mu argument ...) (lambda (f) (f argument ...)))))
(define m (mu 1 2 3))
(define v (lambda () (values 1 2 3)))
(define mm (lambda (x)
(if (< x 0)
(mu 1 2 3)
(if (= x 0)
(mu 4 5 6)
(mu 7 8 9)))))
(define vv (lambda (x)
(if (< x 0)
(values 1 2 3)
(if (= x 0)
(values 4 5 6)
(values 7 8 9)))))
(time (for-each (lambda (x) (m list)) (make-list 100000 1)))
(time (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1)))
(time (for-each (lambda (x) ((mm x) list)) (make-list 100000 1)))
(time (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1)))
1. Mzscheme
Welcome to MzScheme version 301, Copyright (c) 2004-2005 PLT Scheme Inc.
> (time (for-each (lambda (x) (m list)) (make-list 100000 1)))
cpu time: 230 real time: 230 gc time: 70
> (time (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1)))
cpu time: 270 real time: 281 gc time: 70
> (time (for-each (lambda (x) ((mm x) list)) (make-list 100000 1)))
cpu time: 280 real time: 280 gc time: 70
> (time (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1)))
cpu time: 310 real time: 311 gc time: 80
2. Chicken
Version 1, Build 66 - linux-unix-gnu-x86
(c)2000-2004 Felix L. Winkelmann
Using hygienic macros
; loading /usr/local/share/chicken/chicken-highlevel-macros.scm ...
#;14> (time (for-each (lambda (x) (m list)) (make-list 100000 1)))
0.23 seconds elapsed
0.03 seconds in (major) GC
0 mutations
974 minor GCs
1 major GCs
#;15> (time (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1)))
0.31 seconds elapsed
0.03 seconds in (major) GC
0 mutations
1340 minor GCs
1 major GCs
#;25> (time (for-each (lambda (x) ((mm x) list)) (make-list 100000 1)))
0.44 seconds elapsed
0.02 seconds in (major) GC
0 mutations
2295 minor GCs
1 major GCs
#;26> (time (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1)))
0.55 seconds elapsed
0.02 seconds in (major) GC
0 mutations
2661 minor GCs
1 major GCs
3. MIT Scheme
Scheme Microcode Version 14.8
MIT Scheme running under GNU/Linux
Type `^C' (control-C) followed by `H' to obtain information about interrupts.
Scheme saved on Friday March 15, 2002 at 12:00:53 AM
Release 7.7.0
Microcode 14.8
Runtime 15.0
SF 4.40
Liar (Intel i386) 4.115
Edwin 3.112
1 ]=> (with-timings
(lambda () (for-each (lambda (x) (m list)) (make-list 100000 1)))
(lambda (run-time gc-time real-time)
(write (internal-time/ticks->seconds run-time))
(write-char #\space)
(write (internal-time/ticks->seconds gc-time))
(write-char #\space)
(write (internal-time/ticks->seconds real-time))
(newline)))
.27 .2 .47
;Unspecified return value
1 ]=> (with-timings
(lambda () (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1)))
(lambda (run-time gc-time real-time)
(write (internal-time/ticks->seconds run-time))
(write-char #\space)
(write (internal-time/ticks->seconds gc-time))
(write-char #\space)
(write (internal-time/ticks->seconds real-time))
(newline)))
.56 .3 .873
;Unspecified return value
1 ]=> (with-timings
(lambda () (for-each (lambda (x) ((mm x) list)) (make-list 100000 1)))
(lambda (run-time gc-time real-time)
(write (internal-time/ticks->seconds run-time))
(write-char #\space)
(write (internal-time/ticks->seconds gc-time))
(write-char #\space)
(write (internal-time/ticks->seconds real-time))
(newline)))
.66 .3 .971
;Unspecified return value
1 ]=> (with-timings
(lambda () (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1)))
(lambda (run-time gc-time real-time)
(write (internal-time/ticks->seconds run-time))
(write-char #\space)
(write (internal-time/ticks->seconds gc-time))
(write-char #\space)
(write (internal-time/ticks->seconds real-time))
(newline)))
.98 .3 1.294
;Unspecified return value
4. Scheme48
Welcome to Scheme 48 1.3 (made by soo on Mon Jul 11 09:51:36 2005)
Copyright (c) 1993-2005 by Richard Kelsey and Jonathan Rees.
Please report bugs to xxxxxx@s48.org.
Get more information at http://www.s48.org/.
Type ,? (comma question-mark) for help.
> ,time (for-each (lambda (x) (m list)) (make-list 100000 1))
Run time: 0.46 seconds; Elapsed time: 0.47 seconds
#{Unspecific}
> ,time (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1))
Run time: 0.56 seconds; Elapsed time: 0.56 seconds
#{Unspecific}
> ,time (for-each (lambda (x) ((mm x) list)) (make-list 100000 1))
Run time: 0.62 seconds; Elapsed time: 0.65 seconds
#{Unspecific}
> ,time (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1))
Run time: 0.73 seconds; Elapsed time: 0.76 seconds
#{Unspecific}
5. Petite Chez Scheme
Petite Chez Scheme Version 7.0
Copyright (c) 1985-2005 Cadence Research Systems
Linked with Pthreads-Win32 under GNU LGPL
http://sources.redhat.com/pthreads-win32/
Copyright (c) 1998 John E. Bossom
Copyright (c) 1999,2002 Pthreads-win32 contributors
> (time (for-each (lambda (x) (m list)) (make-list 100000 1)))
(time (for-each (lambda (...) ...) ...))
3 collections
90 ms elapsed cpu time, including 20 ms collecting
90 ms elapsed real time, including 20 ms collecting
3200680 bytes allocated, including 5678856 bytes reclaimed
> (time (for-each (lambda (x) (call-with-values v list)) (make-list 100000 1)))
(time (for-each (lambda (...) ...) ...))
3 collections
100 ms elapsed cpu time, including 20 ms collecting
100 ms elapsed real time, including 20 ms collecting
3200680 bytes allocated, including 3271304 bytes reclaimed
> (time (for-each (lambda (x) ((mm x) list)) (make-list 100000 1)))
(time (for-each (lambda (...) ...) ...))
4 collections
190 ms elapsed cpu time, including 40 ms collecting
190 ms elapsed real time, including 40 ms collecting
4000904 bytes allocated, including 3537112 bytes reclaimed
> (time (for-each (lambda (x) (call-with-values (lambda () (vv x)) list)) (make-list 100000 1)))
(time (for-each (lambda (...) ...) ...))
4 collections
201 ms elapsed cpu time, including 50 ms collecting
210 ms elapsed real time, including 70 ms collecting
4800904 bytes allocated, including 5963232 bytes reclaimed
|QUOTE: A solution would be to enclose the arguments of VALUES expression
|QUOTE: in a procedure of one argument, a consumer procedure of QUOTE:
|CALL-WITH-VALUS. How does this SRFI address the efficiency problem? Looking
|at the implementation section, I see many calls to
|call-with-current-continuation. Is that not somewhat slow under some
|circumstances? Looking further down, there are many recursive procedures and
|many assignments that are performed at runtime. Maybe your intension is to
|have a reference implementation outlining the concept and implementors are
|encouraged to provide their own implementations. If that's the case, it may
|be a good idea to state it in the implementation section.
How many calls to call-with-current-continuation are there?
CALL-WITH-CURRENT-CONTINUATION is used only once in implementation of ALET[*]
for escaspe function, so if you don't use the function, there will be no
problem.
Recursive procedures are the same. They are used only for recursive function
like named-let[*].
There is only one additional assignment, in single value binding of ALET
implementation. It is for sequential binding from left to right.
Thanks for comments.
--
Joo ChurlSoo