will iterate at most ten times but may stop sooner if list contains fewer than ten items.
Counting Loops
Arithmetic iteration clauses control the number of times the loop body will be executed by stepping a variable over a range of numbers, executing the body once per step. These clauses consist of from one to three of the following prepositional phrases after the for (or as): the from where phrase, the to where phrase, and the by how much phrase.
The from where phrase specifies the initial value of the clause's variable. It consists of one of the prepositions from, downfrom, or upfrom followed by a form, which supplies the initial value (a number).
The to where phrase specifies a stopping point for the loop and consists of one of the prepositions to, upto, below, downto, or above followed by a form, which supplies the stopping point. With upto and downto, the loop body will be terminated (without executing the body again) when the variable passes the stopping point; with below and above, it stops one iteration earlier.The by how much phrase consists of the prepositions by and a form, which must evaluate to a positive number. The variable will be stepped (up or down, as determined by the other phrases) by this amount on each iteration or by one if it's omitted.
You must specify at least one of these prepositional phrases. The defaults are to start at zero, increment the variable by one at each iteration, and go forever or, more likely, until some other clause terminates the loop. You can modify any or all of these defaults by adding the appropriate prepositional phrases. The only wrinkle is that if you want decremental stepping, there's no default from where value, so you must specify one with either from or downfrom. So, the following:
(loop for i upto 10 collect i)
collects the first eleven integers (zero to ten), but the behavior of this:
(loop for i downto -10 collect i) ; wrong
is undefined. Instead, you need to write this:
(loop for i from 0 downto -10 collect i)
Also note that because LOOP is a macro, which runs at compile time, it has to be able to determine the direction to step the variable based solely on the prepositions—not the values of the forms, which may not be known until runtime. So, the following:
(loop for i from 10 to 20 ...)
works fine since the default is incremental stepping. But this:
(loop for i from 20 to 10 ...)
won't know to count down from twenty to ten. Worse yet, it won't give you an error—it will just not execute the loop since i is already greater than ten. Instead, you must write this:
(loop for i from 20 downto 10 ...)
or this:
(loop for i downfrom 20 to 10 ...)
Finally, if you just want a loop that repeats a certain number of times, you can replace a clause of the following form:
for i from 1 to number-form
with a repeat clause like this:
repeat number-form
These clauses are identical in effect except the repeat clause doesn't create an explicit loop variable.
Looping Over Collections and Packages
The for clauses for iterating over lists are much simpler than the arithmetic clauses. They support only two prepositional phrases, in and on.
A phrase of this form:
for var in list-form
steps var over all the elements of the list produced by evaluating list-form.
(loop for i in (list 10 20 30 40) collect i) ==> (10 20 30 40)
Occasionally this clause is supplemented with a by phrase, which specifies a function to use to move down the list. The default is CDR but can be any function that takes a list and returns a sublist. For instance, you could collect every other element of a list with a loop like this:
(loop for i in (list 10 20 30 40) by #'cddr collect i) ==> (10 30)
An on prepositional phrase is used to step var over the cons cells that make up a list.
(loop for x on (list 10 20 30) collect x) ==> ((10 20 30) (20 30) (30))
This phrase too can take a by preposition:
(loop for x on (list 10 20 30 40) by #'cddr collect x) ==> ((10 20 30 40) (30 40))
Looping over the elements of a vector (which includes strings and bit vectors) is similar to looping over the elements of a list except the preposition across is used instead of in.[236] For instance:
(loop for x across "abcd" collect x) ==> (#\a #\b #\c #\d)
Iterating over a hash table or package is slightly more complicated because hash tables and packages have different sets of values you might want to iterate over—the keys or values in a hash table and the different kinds of symbols in a package. Both kinds of iteration follow the same pattern. The basic pattern looks like this:
(loop for var being the things in hash-or-package ...)
For hash tables, the possible values for things are hash-keys and hash-values, which cause var to be bound to successive values of either the keys or the values of the hash table. The hash-or-package form is evaluated once to produce a value, which must be a hash table.
To iterate over a package, things can be symbols, present-symbols, and external-symbols, which cause var to be bound to each of the symbols accessible in a package, each of the symbols present in a package (in other words, interned or imported into that package), or each of the symbols that have been exported from the package. The hash-or-package form is evaluated to produce the name of a package, which is looked up as if by FIND-PACKAGE or a package object. Synonyms are also available for parts of the for clause. In place of the, you can use each; you can use of instead of in; and you can write the things in the singular (for example, hash-key or symbol).
Finally, since you'll often want both the keys and the values when iterating over a hash table, the hash table clauses support a using subclause at the end of the hash table clause.
(loop for k being the hash-keys in h using (hash-value v) ...)
(loop for v being the hash-values in h using (hash-key k) ...)
Both of these loops will bind k to each key in the hash table and v to the corresponding value. Note that the first element of the using subclause must be in the singular form.[237]
Equals-Then Iteration
If none of the other for clauses supports exactly the form of variable stepping you need, you can take complete control over stepping with an equals-then clause. This clause is similar to the binding clauses in a DO loop but cast in a more Algolish syntax. The template is as follows:
236
You may wonder why LOOP can't figure out whether it's looping over a list or a vector without needing different prepositions. This is another consequence of LOOP being a macro: the value of the list or vector won't be known until runtime, but LOOP, as a macro, has to generate code at compile time. And LOOP's designers wanted it to generate extremely efficient code. To be able to generate efficient code for looping across, say, a vector, it needs to know at compile time that the value will be a vector at runtime—thus, the different prepositions are needed.
237
Don't ask me why LOOP's authors chickened out on the no-parentheses style for the using subclause.