4

Sometime, I need to iterate $n$ times where $n$ is the number of elements in a list. Of course, I could write something like:

(loop for i from 0 below (list-length l)
      do something)

But I like to write rather:

(loop for i from 0
      for u in l ; unused 'u' variable
      do something)

where the for u in l part is merely intended to stop the loop after $n$ iterations. But then I don't use the u variable, and the interpreter keeps complaining. Is there some way to handle this style of coding? Should I avoid it and use list-length instead?

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
Thomas Baruchel
  • 7,236
  • 2
  • 27
  • 46
  • Did you consider using `dotimes` or `dolist`? – Martin Půda Jul 14 '22 at 15:42
  • Your code is more efficient, but unless your lists are unusually long or this is a critical path, then it's probably premature optimization. The `list-length` version is definitely more clear. To answer the actual question, can you specify which interpreter you're using / care about? Disabling interpreter warnings is likely to be an interpreter-specific technique – Silvio Mayolo Jul 14 '22 at 15:44
  • 1
    @MartinPůda It is not the same thing; I really need all the power of the `loop` macro for computing sophisticated independent sequences; the whole thing is that I want exactly as many terms as in l. – Thomas Baruchel Jul 14 '22 at 16:40

3 Answers3

5
(loop for i from 0
      for NIL in l
      do something)

NIL should do it.

The LOOP destructuring pattern can be empty and the rest list elements are ignored. Additionally: In a LOOP destructuring pattern, NIL indicates that the variable is not used.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • 2
    Thank you for that; this is really what I was asking for! I could have explained my question a little better by referring to the "throwable variable" in other languages (underscore in Python), but you perfectly understood the point. – Thomas Baruchel Jul 16 '22 at 18:57
  • This is just a really useful thing to know! Thanks! – ignis volens Jul 18 '22 at 14:28
1

Try the repeat clause:

(loop repeat (length l) ...)

The argument expression of the repeat clause is required to be evaluated once.

Kaz
  • 55,781
  • 9
  • 100
  • 149
0

One horrible hack to do this which does not involve any extra traversals and if you really need to use loop is:

(defun foo (l)
  (loop for i upfrom 0
        for u = l then (cdr u)
          while (consp u)
        collect i))

But probably Kaz's answer of (loop repeat (length l) ...) is fine in practice, if you must use loop.

ignis volens
  • 7,040
  • 2
  • 12