The following shows a typical situation where one wishes for a collecting macro:
There are two basic forms of collecting:
- collect into a single container (and yield the list), like above. It usually takes a form similar to:
A simple implementation of the first idiom uses MACROLET to locally define the inner COLLECT operator:
It also uses tail-consing, which was measured by Sam Steingold to be more performant than the PUSH/NREVERSE idiom on several implementations (TODO Reference, c.l.l April 1999 or elsewhere). OTOH, there's an article by Richard C. Waters from 1993 comparing NREVERSE and RPLACD (aka. SETF CDR) where NREVERSE usually wins, presumably because it is heavily optimized by the implementation.
As of November 2001, yet another discussion about the design of a collecting facility for the second situation is going on in comp.lang.lisp under "Collection utilities".
Do you prefer
Several people have posted their own versions in the long history of c.l.l. IIRC among others Tim Bradshaw (both cases), Bruno Haible, Sam Steingold, and more recently, a naive implementation by Chris Capel. Helmut Eller points at the COLLECT macro available in CMUCL:
A version of with-collect is distributed with CLISP and CLOCC in CLLIB/simple.lisp:
One could also use an adjustable array and VECTOR-PUSH-EXTEND instead of lists, but that's another story (See c.l.l around November 2001 about "Loop? ptooey" for Dylan code from Bruce Hoult for a generic collecting macro that works on arrays, lists etc.).
Topics: accumulators, language extension