Question: Lisp: Collect multiple lists in loop

Question

Lisp: Collect multiple lists in loop

Answers 2
Added at 2016-12-28 17:12
Tags
Question

I want to be able to collect multiple lists inside a loop.

I know this can be done without a loop, however I was wondering whether this would be possible with a loop as well. I'd like something like this:

  (loop for var in list
        (if (cond1 var)
            (if (cond2 var)
                collect into list1
                collect into list2))
        finally (list list1 list2))

I get the error that the LOOP keyword is expected, I guess the collect should be used right after a when or a loop. Is there any way to solve that?

Answers
nr: #1 dodano: 2016-12-28 17:12

Believe it or not you have too many parentheses. loop has its own little sublanguage which is quite different from Common Lisp s-expressions.

(loop :for var :in list
      :when (cond1 var)
        :if (cond2 var)
           :collect var :into list1
        :else
           :collect var :into list2
        :end
      :end
      :finally (return (list list1 list2)))

In addition I specify what to :collect and :finally just evaluates so you need to use (return ...) or else you can expect nil.

I use keywords for loop keywords to distinguish them from other symbols. It's just style. The indentation is of course ignored and just for readability, but :end isn't. However in this case both :end keywords are redundant since the loop is parsed correctly without them.

I'm by no means a loop wiz.. Every time I get something slightly complex I tend to use Land of Lisp's Periodic table or Loop for black belts, a chapter from Practical Common Lisp.

Periodic table of Loop Macro

nr: #2 dodano: 2016-12-28 18:12

You have a couple of problems.

First, if you want to put normal Lisp code into the loop body, you need the do keyword. But you could use do's when or if keywords instead.

Second, the collect keyword requires you to specify an expression to collect into the list, e.g. collect var into list1.

Third, you need to use (return expression) to return a value from the form in the finally clause.

  (loop for var in list
    when (cond1 var)
      if (cond2 var)
        collect var into list1
      else
        collect var into list2
    finally (return (list list1 list2)))
Source Show
◀ Wstecz