From: Thomas F. Burdick
Subject: Collection utilities
Date: 
Message-ID: <xcvsnbgix4v.fsf@famine.OCF.Berkeley.EDU>
So, speaking of collection utilities, perhaps a collection macro would
be a good addition to the growing list of Common Lisp Utilities in
CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.  I was
trying to think of different styles of collection macros, and I think
I've only seen 5 variations (or at least, that's all I can think of).

  (collecting
    ... (collect foo) ...)
  => collected list                                      ; style 1
  
  (with-collections (a b c)
    ... (collect foo :into a)
    ... (collect bar :into b)
    ... (collect baz :into c)
    ... 'qux)
  => QUX                                                 ; style 2
   or
  => the values of the collected lists, in order, a b c  ; style 3
  
  (with-collectors (a b c)
    ... (a foo)
    ... (b bar)
    ... (c baz)
    ... 'qux)
  => QUX                                                 ; style 4
   or
  => the values of the collected lists, in order, a b c  ; style 5

I guess first of all, does anyone have any other styles?

If not, of these above, I think style 4 is preferable.  I like the
idea of having the list in a variable, and being able to call a
collector macro/function of the same name to collect into it.  Styles
2 and 3 have syntax nicely parallel to loop's collect/collecting
keyword, but a simple macro could let you do that with styles 4 or 5.
Finally, I think it makes sense to have the body be a progn, rather
than returning all the collected lists, because it's more flexible,
and it's easy enough to write (values a b c) at the end, if that's
what you want.

Anyone have any feelings on these?

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               

From: Vebjorn Ljosa
Subject: Re: Collection utilities
Date: 
Message-ID: <cy3r8r07cdi.fsf@ljosa.com>
* ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick)
| So, speaking of collection utilities, perhaps a collection macro would
| be a good addition to the growing list of Common Lisp Utilities in
| CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.  I was
| trying to think of different styles of collection macros, and I think
| I've only seen 5 variations (or at least, that's all I can think of).
| 
|   (collecting
|     ... (collect foo) ...)
|   => collected list                                      ; style 1
|   
|   (with-collections (a b c)
|     ... (collect foo :into a)
|     ... (collect bar :into b)
|     ... (collect baz :into c)
|     ... 'qux)
|   => QUX                                                 ; style 2
|    or
|   => the values of the collected lists, in order, a b c  ; style 3
|   
|   (with-collectors (a b c)
|     ... (a foo)
|     ... (b bar)
|     ... (c baz)
|     ... 'qux)
|   => QUX                                                 ; style 4
|    or
|   => the values of the collected lists, in order, a b c  ; style 5
| 
| I guess first of all, does anyone have any other styles?

I like style 2, but I don't see a reason for the :INTO keyword; let's
drop it, but keep the argument order, which is analogous to that of
PUSH:

    (with-collections (a b c)
      (collect foo a)
      (collect bar b)
      (collect baz c)
      'qux)
    => QUX

With style 1 you don't have to give a name to the collection variable,
and this is nice sometimes.  Fortunately, we can add that to style 2
as well:

    (with-collections ()
      (collect foo)
      'qux)
    => QUX

Here, an empty list as argument to WITH-COLLECTION tells it to set up
an anonymous collection variable.  The second argument to COLLECT is
optional; if it's not given, COLLECT adds the element to the anonymous
collection variable.

With nested anonymous WITH-COLLECTION forms, the inner form shadows
the anonymous collection variable of the outer form:

    (with-collections ()
      (collect (with-collections ()
                 (collect :foo)
                 (collect :bar))
      (collect :baz))
    => ((:FOO :BAR) :BAZ)

It think COLLECT should return the new value of the collection
variable.

| If not, of these above, I think style 4 is preferable.  I like the
| idea of having the list in a variable, and being able to call a
| collector macro/function of the same name to collect into it.  

I disagree, for two reasons.  First, style 2 forces me to pick
variable names that are different from the names of functions I intend
to use within the scope of with-collections.  (That is a problem
because I quite often use the same names for variables and functions.)

Second, I think a verb like "collect" is a much better function name
than the names most of the variables I collect things into.  For
instance, CUSTOMERS is a good name for the variable you collect
customer objects into, but I don't think it's a good name for a
function which add such an object to the collection.  (But maybe it
just takes getting used to.)

| Finally, I think it makes sense to have the body be a progn, rather
| than returning all the collected lists, because it's more flexible,
| and it's easy enough to write (values a b c) at the end, if that's
| what you want.

I agree.

Thanks for taking initiative.

-- 
Vebjorn Ljosa
From: Gareth McCaughan
Subject: Re: Collection utilities
Date: 
Message-ID: <slrn9vdpl2.8hp.Gareth.McCaughan@g.local>
Vebjorn Ljosa wrote:

[Thomas Burdick listed some possible syntaxes for collecting
stuff into lists:]

> |   (collecting
> |     ... (collect foo) ...)
> |   => collected list                                      ; style 1
> |   
> |   (with-collections (a b c)
> |     ... (collect foo :into a)
> |     ... (collect bar :into b)
> |     ... (collect baz :into c)
> |     ... 'qux)
> |   => QUX                                                 ; style 2
> |    or
> |   => the values of the collected lists, in order, a b c  ; style 3
> |   
> |   (with-collectors (a b c)
> |     ... (a foo)
> |     ... (b bar)
> |     ... (c baz)
> |     ... 'qux)
> |   => QUX                                                 ; style 4
> |    or
> |   => the values of the collected lists, in order, a b c  ; style 5
> | 
> | I guess first of all, does anyone have any other styles?
> 
> I like style 2, but I don't see a reason for the :INTO keyword; let's
> drop it, but keep the argument order, which is analogous to that of
> PUSH:
...
> With style 1 you don't have to give a name to the collection variable,
> and this is nice sometimes.  Fortunately, we can add that to style 2
> as well:
> 
>     (with-collections ()
>       (collect foo)
>       'qux)
>     => QUX
> 
> Here, an empty list as argument to WITH-COLLECTION tells it to set up
> an anonymous collection variable.  The second argument to COLLECT is
> optional; if it's not given, COLLECT adds the element to the anonymous
> collection variable.

I don't understand how you get at the collected objects
in an anonymous style-2 collection.

-- 
Gareth McCaughan  ················@pobox.com
.sig under construc
From: Bruce Hoult
Subject: Re: Collection utilities
Date: 
Message-ID: <bruce-DB5053.22152918112001@news.paradise.net.nz>
In article <·······························@g.local>, 
················@pobox.com wrote:

> Vebjorn Ljosa wrote:
> 
> [Thomas Burdick listed some possible syntaxes for collecting
> stuff into lists:]
> 
> > |   (with-collections (a b c)
> > |     ... (collect foo :into a)
> > |     ... (collect bar :into b)
> > |     ... (collect baz :into c)
> > |     ... 'qux)
> > |   => QUX                                                 ; style 2
> > |    or
> > |   => the values of the collected lists, in order, a b c  ; style 3
> 
> I don't understand how you get at the collected objects
> in an anonymous style-2 collection.

You'd need to return them with an explicit (values ...) at the end.

-- Bruce
From: Gareth McCaughan
Subject: Re: Collection utilities
Date: 
Message-ID: <slrn9vgld0.kna.Gareth.McCaughan@g.local>
Bruce Hoult wrote:

> In article <·······························@g.local>, 
> ················@pobox.com wrote:
> 
> > Vebjorn Ljosa wrote:
> > 
> > [Thomas Burdick listed some possible syntaxes for collecting
> > stuff into lists:]
> > 
> > > |   (with-collections (a b c)
> > > |     ... (collect foo :into a)
> > > |     ... (collect bar :into b)
> > > |     ... (collect baz :into c)
> > > |     ... 'qux)
> > > |   => QUX                                                 ; style 2
> > > |    or
> > > |   => the values of the collected lists, in order, a b c  ; style 3
> > 
> > I don't understand how you get at the collected objects
> > in an anonymous style-2 collection.
> 
> You'd need to return them with an explicit (values ...) at the end.

What would go in place of the "..." ? With a non-anonymous
("nymous", I suppose) style-2 collection it's obvious. For
an anonymous one, though?

-- 
Gareth McCaughan  ················@pobox.com
.sig under construc
From: Vebjorn Ljosa
Subject: Re: Collection utilities
Date: 
Message-ID: <cy3wv0m5ph2.fsf@ljosa.com>
* ················@pobox.com (Gareth McCaughan)
| Bruce Hoult wrote:
| 
| > You'd need to return them with an explicit (values ...) at the end.
| 
| What would go in place of the "..." ? With a non-anonymous
| ("nymous", I suppose) style-2 collection it's obvious. For
| an anonymous one, though?

I few examples of how I envision this will work:

(with-collections (a)
  (collect :foo a)
  (collect :bar a)
  'qux)
=> QUX

(with-collections (a)
  (collect :foo a)
  (collect :bar a))
=> (:FOO :BAR)

(with-collections ()
  (collect :foo)
  (collect :bar)
  'qux)
=> QUX

(with-collection ()
  (collect :foo)
  (collect :bar))
=> (:FOO :BAR)

WITH-COLLECTION always returns the value of the last form, just like
PROGN.  COLLECT returns the collection, be it anonymous or not.  If it
doesn't fit to have COLLECT's value returned by the last form, you can
just give the collection a name:

(with-collection (a)
  (collect :foo a)
  (collect :bar a)
  (do-something-else)
  a)
=> (:FOO :BAR)

I'd like to hear opinions from more people.

-- 
Vebjorn Ljosa
From: Software Scavenger
Subject: Re: Collection utilities
Date: 
Message-ID: <a6789134.0111200524.18367946@posting.google.com>
Vebjorn Ljosa <·····@ljosa.com> wrote in message news:<···············@ljosa.com>...

> I'd like to hear opinions from more people.

LOOP is powerful, general, and standard.  E.g.

CL-USER 5 > (loop as i below 5 collect i collect (* i 2))
(0 0 1 2 2 4 3 6 4 8)

And countless other combinations of collecting, seeming to cover just
about everything you could want from a set of collection utilities.

A lot of Lispers dislike LOOP because it's not Lispy enough.  But in
fact good  usage of Lisp is to build your own higher level
sublanguages on top of it, and LOOP is one example of such building,
and is therefore among the most Lispy of Lispisms.
From: Lieven Marchand
Subject: Re: Collection utilities
Date: 
Message-ID: <m3lmh1xupp.fsf@localhost.localdomain>
··········@mailandnews.com (Software Scavenger) writes:

> And countless other combinations of collecting, seeming to cover just
> about everything you could want from a set of collection utilities.
> 
> A lot of Lispers dislike LOOP because it's not Lispy enough.  But in
> fact good  usage of Lisp is to build your own higher level
> sublanguages on top of it, and LOOP is one example of such building,
> and is therefore among the most Lispy of Lispisms.

I like LOOP as much as the next person, but the collect loop keyword
has one problem, viz. that it is a LOOP KEYWORD. You can't use it some
levels deep in computation like (loop ... (with-my-frob (frob foo)
(collect (frizzle frob)))...).

-- 
Lieven Marchand <···@wyrd.be>
She says, "Honey, you're a Bastard of great proportion."
He says, "Darling, I plead guilty to that sin."
Cowboy Junkies -- A few simple words
From: Thomas F. Burdick
Subject: Re: Collection utilities
Date: 
Message-ID: <xcvitc53xi9.fsf@monsoon.OCF.Berkeley.EDU>
Lieven Marchand <···@wyrd.be> writes:

> ··········@mailandnews.com (Software Scavenger) writes:
> 
> > And countless other combinations of collecting, seeming to cover just
> > about everything you could want from a set of collection utilities.
> > 
> > A lot of Lispers dislike LOOP because it's not Lispy enough.  But in
> > fact good  usage of Lisp is to build your own higher level
> > sublanguages on top of it, and LOOP is one example of such building,
> > and is therefore among the most Lispy of Lispisms.
> 
> I like LOOP as much as the next person, but the collect loop keyword
> has one problem, viz. that it is a LOOP KEYWORD. You can't use it some
> levels deep in computation like (loop ... (with-my-frob (frob foo)
> (collect (frizzle frob)))...).

Plus, nesting messes everything up:

  * (loop for pos upfrom 1
          for l in '((a b c) (one two three) (you and me) (girl))
          collect pos into foo
          collect l into foo
          finally (return foo))
  (1 (A B C) 2 (ONE TWO THREE) 3 (YOU AND ME) 4 (GIRL))
  * (loop for pos upfrom 1
          for l in '((a b c) (one two three) (you and me) (girl))
          collect pos into foo
          do (loop for sym in l
                   collect l into foo)
          finally (return foo))
  (1 2 3 4)
  
  ;;; But...
  * (with-collectors (foo)
      (loop for pos upfrom 1
            for l in '((a b c) (one two three) (you and me) (girl))
            do (collect pos :into foo)
            do (loop for sym in l
                     do (collect pos :into foo))
            finally (return foo)))
  (1 A B C 2 ONE TWO THREE 3 YOU AND ME 4 GIRL)
 
And, of course, there are more reasonable, less Jackson-5-related uses.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Gabe Garza
Subject: Re: Collection utilities
Date: 
Message-ID: <itc55a66.fsf@kynopolis.org>
···@monsoon.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Plus, nesting messes everything up:
> 
>   * (loop for pos upfrom 1
>           for l in '((a b c) (one two three) (you and me) (girl))
>           collect pos into foo
>           collect l into foo
>           finally (return foo))
>   (1 (A B C) 2 (ONE TWO THREE) 3 (YOU AND ME) 4 (GIRL))
>   * (loop for pos upfrom 1
>           for l in '((a b c) (one two three) (you and me) (girl))
>           collect pos into foo
>           do (loop for sym in l
>                    collect l into foo)
>           finally (return foo))
>   (1 2 3 4)
>   
>   ;;; But...
>   * (with-collectors (foo)
>       (loop for pos upfrom 1
>             for l in '((a b c) (one two three) (you and me) (girl))
>             do (collect pos :into foo)
>             do (loop for sym in l
>                      do (collect pos :into foo))
>             finally (return foo)))
>   (1 A B C 2 ONE TWO THREE 3 YOU AND ME 4 GIRL)

;;; Or....

* (loop for pos upfrom 1 
      for l in '((a b c) (one two three) (you and me) (girl))
      collect pos
      append l)
(1 A B C 2 ONE TWO THREE 3 YOU AND ME 4 GIRL)


Collect isn't the only accumulator offered by LOOP.

Gabe Garza
From: Kent M Pitman
Subject: Re: Collection utilities
Date: 
Message-ID: <sfwd72dawpd.fsf@shell01.TheWorld.com>
Lieven Marchand <···@wyrd.be> writes:

> ··········@mailandnews.com (Software Scavenger) writes:
> 
> > And countless other combinations of collecting, seeming to cover just
> > about everything you could want from a set of collection utilities.
> > 
> > A lot of Lispers dislike LOOP because it's not Lispy enough.  But in
> > fact good  usage of Lisp is to build your own higher level
> > sublanguages on top of it, and LOOP is one example of such building,
> > and is therefore among the most Lispy of Lispisms.
> 
> I like LOOP as much as the next person, but the collect loop keyword
> has one problem, viz. that it is a LOOP KEYWORD. You can't use it some
> levels deep in computation like (loop ... (with-my-frob (frob foo)
> (collect (frizzle frob)))...).

This is, in case you don't realize it, the reason most of the loop keywords
are there.  All the whole mess with UNLESS and WHEN are there to allow you
to build a "bridge" between the bindings and the collection points in some
of the more common cases.  If we had had better code-walking technology 
reliably available so that we could have done a syntactically separated
COLLECT keyword, LOOP would be simpler. You would say
  do (when foo (collect x))
rather than
  when foo 
    collect x
From: Lieven Marchand
Subject: Re: Collection utilities
Date: 
Message-ID: <m3pu6crlil.fsf@localhost.localdomain>
Kent M Pitman <······@world.std.com> writes:

> This is, in case you don't realize it, the reason most of the loop keywords
> are there.  All the whole mess with UNLESS and WHEN are there to allow you
> to build a "bridge" between the bindings and the collection points in some
> of the more common cases. 

I was aware of it. I recently discovered the ELSE parts of WHEN and
UNLESS etc.  In fact, if John didn't dislike LOOP so much, a lot of
his IF* code could be rewritten as

(loop repeat 1
      when first-condition
      do
      .... a lot of forms
      else
      .... a lot of forms)

;-)

-- 
Lieven Marchand <···@wyrd.be>
She says, "Honey, you're a Bastard of great proportion."
He says, "Darling, I plead guilty to that sin."
Cowboy Junkies -- A few simple words
From: Vebjorn Ljosa
Subject: Re: Collection utilities
Date: 
Message-ID: <cy34rnqemmv.fsf@ljosa.com>
* ················@pobox.com (Gareth McCaughan)
| Vebjorn Ljosa wrote:
| 
| > With style 1 you don't have to give a name to the collection variable,
| > and this is nice sometimes.  Fortunately, we can add that to style 2
| > as well:
| > 
| >     (with-collections ()
| >       (collect foo)
| >       'qux)
| >     => QUX
| > 
| > Here, an empty list as argument to WITH-COLLECTION tells it to set up
| > an anonymous collection variable.  The second argument to COLLECT is
| > optional; if it's not given, COLLECT adds the element to the anonymous
| > collection variable.
| 
| I don't understand how you get at the collected objects
| in an anonymous style-2 collection.

You don't.  But that is fine sometimes; often you just want to return
the collection at the end, you don't care about its intermediate
values.  And in those cases it's nice not to have to make up a name
for the collection.

Of course the collection has to be returned somehow.  Two solutions:
(1)�WITH-COLLECTIONS always returns the collection(s).
(2)�WITH-COLLECTION always returns the value(s) of its last form, and
COLLECT returns the collection it collects into.  I think I prefer
number (2).

-- 
Vebjorn Ljosa
From: Barry Margolin
Subject: Re: Collection utilities
Date: 
Message-ID: <a2SI7.7$I25.1652@burlma1-snr2>
In article <···············@famine.OCF.Berkeley.EDU>,
Thomas F. Burdick <···@famine.OCF.Berkeley.EDU> wrote:
>So, speaking of collection utilities, perhaps a collection macro would
>be a good addition to the growing list of Common Lisp Utilities in

You mean like Dick Waters's Series mechanism, described in Appendix A of
CLTL2?

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Helmut Eller
Subject: Re: Collection utilities
Date: 
Message-ID: <m24rnsgy2k.fsf@xaital.online-marketwatch.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> So, speaking of collection utilities, perhaps a collection macro would
> be a good addition to the growing list of Common Lisp Utilities in
> CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.  I was
> trying to think of different styles of collection macros, and I think
> I've only seen 5 variations (or at least, that's all I can think of).
> 
>   (collecting
>     ... (collect foo) ...)
>   => collected list                                      ; style 1
>   
>   (with-collections (a b c)
>     ... (collect foo :into a)
>     ... (collect bar :into b)
>     ... (collect baz :into c)
>     ... 'qux)
>   => QUX                                                 ; style 2
>    or
>   => the values of the collected lists, in order, a b c  ; style 3
>   
>   (with-collectors (a b c)
>     ... (a foo)
>     ... (b bar)
>     ... (c baz)
>     ... 'qux)
>   => QUX                                                 ; style 4
>    or
>   => the values of the collected lists, in order, a b c  ; style 5
> 
> I guess first of all, does anyone have any other styles?

CMUCL has a macro `collect', similar to style 4: 

   (collect ((Name [Initial-Value [Function]])...) 
	Form...)

Here is an example:

   (collect ((c1) (c2 '(init) cons)) 
     (dolist (e '(x y z)) 
       (c1 e)	
       (c2 e))
     (values (c1) (c2)))	
  => (x y z) and (z y x init)

The final value of a collector can be obtained by calling the
macro without arguments, e.g (c1).

I like this style because 
  1) it is used in CMUCL (and SBCL)
  2) it is more general than the other styles.

--
Helmut Eller

 
From: Sam Steingold
Subject: Re: Collection utilities
Date: 
Message-ID: <ur8qtxwgb.fsf@xchange.com>
> * In message <···············@famine.OCF.Berkeley.EDU>
> * On the subject of "Collection utilities"
> * Sent on 14 Nov 2001 18:30:24 -0800
> * Honorable ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>
> So, speaking of collection utilities, perhaps a collection macro would
> be a good addition to the growing list of Common Lisp Utilities in
> CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.

see WITH-COLLECT in CLOCC/CLLIB/simple.lisp
<http://www.podval.org/~sds/data/cllib.html>
(It is also included with CLISP)

(with-collect (c1 c2) (dotimes (i 10) (if (oddp i) (c1 i) (c2 i))))
 ==> (1 3 5 7 9); (0 2 4 6 8) [2 values]

-- 
Sam Steingold (http://www.podval.org/~sds)
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>
Isn't "Microsoft Works" an advertisement lie?
From: Christophe Rhodes
Subject: Re: Collection utilities
Date: 
Message-ID: <sqpu6d1ky8.fsf@cam.ac.uk>
Sam Steingold <···@gnu.org> writes:

> > * Honorable ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> >
> > So, speaking of collection utilities, perhaps a collection macro would
> > be a good addition to the growing list of Common Lisp Utilities in
> > CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.
> 
> see WITH-COLLECT in CLOCC/CLLIB/simple.lisp
> <http://www.podval.org/~sds/data/cllib.html>
> (It is also included with CLISP)
> 
> (with-collect (c1 c2) (dotimes (i 10) (if (oddp i) (c1 i) (c2 i))))
>  ==> (1 3 5 7 9); (0 2 4 6 8) [2 values]

Can you tell us how you decided that this design was optimal?

Thanks,

Christophe
-- 
Jesus College, Cambridge, CB5 8BL                           +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/                  (defun pling-dollar 
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)
From: Sam Steingold
Subject: Re: Collection utilities
Date: 
Message-ID: <ulmh1xtmf.fsf@xchange.com>
> * In message <··············@cam.ac.uk>
> * On the subject of "Re: Collection utilities"
> * Sent on 20 Nov 2001 16:11:27 +0000
> * Honorable Christophe Rhodes <·····@cam.ac.uk> writes:
>
> Sam Steingold <···@gnu.org> writes:
> 
> > > * Honorable ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> > >
> > > So, speaking of collection utilities, perhaps a collection macro would
> > > be a good addition to the growing list of Common Lisp Utilities in
> > > CLiki <http://ww.telent.net/cliki/Common%20Lisp%20Utilities>.
> > 
> > see WITH-COLLECT in CLOCC/CLLIB/simple.lisp
> > <http://www.podval.org/~sds/data/cllib.html>
> > (It is also included with CLISP)
> > 
> > (with-collect (c1 c2) (dotimes (i 10) (if (oddp i) (c1 i) (c2 i))))
> >  ==> (1 3 5 7 9); (0 2 4 6 8) [2 values]
> 
> Can you tell us how you decided that this design was optimal?

it's lispy (returns values) and simple, and similar to LOOP.


-- 
Sam Steingold (http://www.podval.org/~sds)
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>
"Syntactic sugar causes cancer of the semicolon."	-Alan Perlis