(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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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
You mean like Dick Waters's Series mechanism, described in Appendix A of
CLTL2?
--
Barry Margolin, bar...@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.
[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 Gareth.M...@pobox.com
.sig under construc
> 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
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
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
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
> 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.
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?
> > * Honorable t...@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)
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
> 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 <m...@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
> cubic...@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.
> cubic...@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
> 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
> 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)
;-)