Hacker News new | ask | show | jobs
by lispm 1345 days ago
> But collecting values has nothing to do with iterating or looping. It should be a separate construct.

I don't care about such rules.

Personally I have no problem using:

  (loop for i below 100 when (primep i) collect i)
1 comments

> I don't care about such rules.

Yes, that is clear.

> Personally I have no problem using:

Loop is fine for simple examples like this. But I am currently maintaining a code base that has LOOPs with dozens and dozens -- sometimes a few hundred -- clauses. A single LOOP can extend over multiple pages. It's a nightmare.

Note that LOOP can fail even for simple examples. Suppose I have a list of lists of numbers and I want to collect all the prime numbers. With WITH-COLLECTOR I can do this:

    (with-collector collect
      (dolist (l1 l)
        (dolist (n l1)
          (if (primep n) (collect n)))))
But with LOOP I can't because there is no way for an inner loop to collect into a collector bound in an outer loop. I have to collect the individual sub-lists and then append them, or something like that, which is both inelegant and inefficient.

And if I have a tree of items which I want to walk over and collect all of the once satisfying a predicate, LOOP just doesn't handle that at all. But by separating collection from iteration it becomes trivial:

    (with-collector collect
      (do-tree (item tree)
        (if (predicate item) (collect item))))
Neither WITH-COLLECTOR and DO-TREE are part of CL, of course, but writing them is an elementary exercise (and both are part of ergolib if you really don't want to be bothered).