Re: Request for Clarification on Rationale Joo ChurlSoo 05 Apr 2006 12:42 UTC

 *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 scheme-48xxxxxx@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