porky11
porky11

Reputation: 962

Common Lisp loop-macro also collect rest

I wanted to split a sequence using LOOP. I thought the easiest way would be a loop collecting all elements, but this seems not to be possible with loop. It would look this way:

(loop for i in '(1 2 3 4 5) with-rest rest
      if (not (= i 3))
      collect i
      else
      return (values i rest))

It should return the values (1 2) and (3 4 5)(or maybe (4 5) as second value). Is there a keyword in loop that can do this (or in the iterate system), or is this only possible by writing new macros (or using tagbody)?

Upvotes: 1

Views: 233

Answers (2)

Xach
Xach

Reputation: 11854

One terse option that avoids LOOP, but traverses part of the list twice:

(let ((tail (member 3 list)))
  (values (ldiff tail list) tail))

Upvotes: 2

Rainer Joswig
Rainer Joswig

Reputation: 139261

LOOP can destructure lists into head and tail. Then one would not use in, but on. You can also collect into a variable.

CL-USER 13 > (loop for (i . rest) on '(1 2 3 4 5)
                   if (not (= i 3))
                   collect i into head
                   else return (values head (cons i rest)))
(1 2)
(3 4 5)

or

CL-USER 16 > (loop with list = '(1 2 3 4 5)
                   for i in list
                   for rest on (rest list)
                   if (not (= i 3))
                   collect i into head
                   else return (values head (cons i rest)))
(1 2)
(3 4 5)

Upvotes: 3

Related Questions