From: Gerard Henri Rene Milmeister
Subject: Common Lisp summary and multiple value binding
Date: 
Message-ID: <2mp483$p8h@neptune.inf.ethz.ch>
I have 2 questions:

1. Is there a summary of the Common Lisp functions as defined in CLtL1, 
   available via ftp.
   I don't have the book, is it still sold (the 1984 version)
2. What is the purpose of VALUES and multiple value bindings. Why not
   use a simple list as return value. Is it because, you can discard but
   the first value with this approach (not a sufficent reason), or are
   there performance reasons.

Gerard

From: Daniel Nesmith
Subject: Re: Common Lisp summary and multiple value bind
Date: 
Message-ID: <2mpd5rINNeu7@sbusol.rz.uni-sb.de>
In article ···@neptune.inf.ethz.ch, ········@iiic.ethz.ch (Gerard Henri Rene Milmeister) writes:
> I have 2 questions:
> 
> 2. What is the purpose of VALUES and multiple value bindings. Why not
>    use a simple list as return value. Is it because, you can discard but
>    the first value with this approach (not a sufficent reason), or are
>    there performance reasons.


Here's an example to test which way is more efficient:

(defun test-list ()
  (let* ((vals (test-list-aux))
	 (x (first vals))	
	 (y (second vals))
	 (z (third vals)))
    x y z))

(defun test-list-aux ()
  (list 'x 'y 'z))

(defun test-values ()
  (multiple-value-bind (x y z)
      (test-values-aux)
    x y z))

(defun test-values-aux ()
  (values 'x 'y 'z))

After compiling (Allegro CL 4.2):

USER(7): (time (dotimes (i 1000) (test-list)))
cpu time (non-gc) 133 msec user, 33 msec system
cpu time (gc)     0 msec user, 0 msec system
cpu time (total)  133 msec user, 33 msec system
real time  203 msec
space allocation:
 10004 cons cells, 0 symbols, 40 other bytes,
NIL
USER(8): (time (dotimes (i 1000) (test-values)))
cpu time (non-gc) 100 msec user, 33 msec system
cpu time (gc)     0 msec user, 0 msec system
cpu time (total)  100 msec user, 33 msec system
real time  130 msec
space allocation:
 7004 cons cells, 0 symbols, 40 other bytes,

So in this case, using multiple values is not only faster, but
it also conses less.  The difference in consing (3000 cells) is easily
explained by the extra three used by (list 'x 'y 'z) on each call
to test-list-aux.

Your mileage may vary.

Dan
From: Karsten Poeck
Subject: Re: Common Lisp summary and multiple value bind
Date: 
Message-ID: <poeck-230394185223@wina65.informatik.uni-wuerzburg.de>
In article <············@sbusol.rz.uni-sb.de>, ·······@cs.uni-sb.de (Daniel
Nesmith) wrote:
> After compiling (Allegro CL 4.2):
> 
> USER(7): (time (dotimes (i 1000) (test-list)))
> cpu time (non-gc) 133 msec user, 33 msec system
>  10004 cons cells, 0 symbols, 40 other bytes,
> USER(8): (time (dotimes (i 1000) (test-values)))
> cpu time (non-gc) 100 msec user, 33 msec system
> space allocation:
>  7004 cons cells, 0 symbols, 40 other bytes,
The space difference is even more impressive in MCL 2.01 on a Quadra 700,
but I really wonder why both functions are 10 times faster on my mac.


? (time (dotimes (i 1000) (test-list)))
(DOTIMES (I 1000) (TEST-LIST)) took 13 milliseconds (0.013 seconds) to run.
Of that, 1 milliseconds (0.001 seconds) were spent in The Cooperative
Multitasking Experience.
 24000 bytes of memory allocated.
NIL
? (time (dotimes (i 1000) (test-values)))
(DOTIMES (I 1000) (TEST-VALUES)) took 8 milliseconds (0.008 seconds) to
run.
NIL
From: Simon Leinen
Subject: Re: Common Lisp summary and multiple value bind
Date: 
Message-ID: <SIMON.94Mar24123334@liasg3.epfl.ch>
Karsten> The space difference is even more impressive in MCL 2.01 on a
Karsten> Quadra 700, but I really wonder why both functions are 10
Karsten> times faster on my mac.

Fortunately (or unfortunately for you MCL users :-), both differences
can easily be explained as artifacts of the benchmarking method.
Daniel compiled the TEST-LIST and TEST-VALUES functions, but then
called (TIME (DOTIMES (I 1000) (TEST-xxx))).  In Allegro, the DOTIMES
is evaluated by an interpreter, so the time is dominated by the
overhead of the DOTIMES.  MCL either has a very fast interpreter, or
it (like some other recent Lisps) uses compilation even for
interactive top-level forms.

If you put the loops into functions:
	(defun test-list-loop (n) (dotimes (i n) (test-list)))
etc., and compile these functions, too, you get much better results on
Allegro (this is 4.2 on an R4000 Indigo - excellent combo by the way!):

USER(110): (time (test-list-loop 1000))
; cpu time (non-gc) 10 msec user, 0 msec system
; cpu time (gc)     0 msec user, 0 msec system
; cpu time (total)  10 msec user, 0 msec system
; real time  3 msec
; space allocation:
 3,001 cons cells,;  0 symbols, 40 other bytes
NIL
USER(111): (time (test-values-loop 1000))
; cpu time (non-gc) 0 msec user, 0 msec system
; cpu time (gc)     0 msec user, 0 msec system
; cpu time (total)  0 msec user, 0 msec system
; real time  2 msec
; space allocation:
 1 cons cell,;  0 symbols, 40 other bytes
NIL

This looks more reasonable: 40 other bytes are allocated by TIME, one
cons cell by the interpreter, and 3000 cons cells by 1000 lists with
three elements each.

Note that TEST-VALUES is now too fast to be measured at 1000
iterations.  If I increase the loop count to a million, I get
1480/1507msec user/real time for TEST-VALUES and 3250/3475msec for
TEST-LIST.  The overhead of the loop will still play a major role, but
you can already say that passing three values as a list is *at least*
twice as expensive than passing them as - three values.
-- 
Simon.
From: Richard Lynch
Subject: Re: Common Lisp summary and multiple value bind
Date: 
Message-ID: <lynch-240394165557@lynch.ils.nwu.edu>
In article <···················@liasg3.epfl.ch>, ·····@lia.di.epfl.ch
(Simon Leinen) wrote:

| called (TIME (DOTIMES (I 1000) (TEST-xxx))).  In Allegro, the DOTIMES
| is evaluated by an interpreter, so the time is dominated by the
| overhead of the DOTIMES.  MCL either has a very fast interpreter, or
| it (like some other recent Lisps) uses compilation even for
| interactive top-level forms.

MCL compiles everything before executing it.

-- 
-- 
--
-- "TANSTAAFL"  Rich ·····@ils.nwu.edu
From: Barry Margolin
Subject: Re: Common Lisp summary and multiple value binding
Date: 
Message-ID: <2mskoaINN3l6@early-bird.think.com>
In article <··········@neptune.inf.ethz.ch> ········@iiic.ethz.ch (Gerard Henri Rene Milmeister) writes:
>1. Is there a summary of the Common Lisp functions as defined in CLtL1, 
>   available via ftp.

I don't think I've ever seen such a summary.

>   I don't have the book, is it still sold (the 1984 version)

All the CLtL1 text is included in CLtL2 (new text is annotated with change
bars).

>2. What is the purpose of VALUES and multiple value bindings. Why not
>   use a simple list as return value. Is it because, you can discard but
>   the first value with this approach (not a sufficent reason), or are
>   there performance reasons.

Others have demonstrated the performance reasons.  The other reason you
mentioned is also part of it.  You can write (+ (floor number1) (floor
number2)) rather than (+ (car (floor number1)) (car (floor number2))).
This was important because Common Lisp was intended to be mostly upward
compatible with MacLisp and Interlisp.  It allowed multiple values to be
added to these functions without requiring all calls of them to change to
discard the extra values, or coming up with new names for the multi-valued
versions of these functions.

Finally, it supports the idea of named return values, analogous to named
arguments, in the MULTIPLE-VALUE-BIND special form:

(multiple-value-bind (floor remainder) (floor number1)
  ...)

However, X3J13 later added DESTRUCTURING-BIND to the language, so this has
less justification.  And had we not put multiple values into the language
in the first place, I suspect DESTRUCTURING-BIND would have been there all
along.

Finally, I think it was just an esthetic choice.  It seemed more
appropriate to use an explicit notation for returning multiple values.  One
might just as well ask why multiple arguments are needed; the language
could just as easily have had only one-argument functions and require the
caller to package them all into a list.  (If you're wondering how you would
build the argument list without an n-argument LIST or a 2-argument CONS, I
suspect it can be done using lexical closures and NCONS -- (ncons x) ==
(cons x nil).)
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar