Iteration control clauses allow direction of loop
iteration.
The loop keywords for
and as
designate iteration control clauses.
Iteration control clauses differ with respect to the specification of
termination tests and to the initialization and stepping1
of loop variables. Iteration clauses by themselves do not cause the Loop Facility to return values, but they can be used in conjunction with value-accumulation clauses to return values.
All variables are initialized in the loop prologue.
A variable binding has lexical scope
unless it is proclaimed special
;
thus, by default, the variable can be accessed only by forms
that lie textually within the loop
.
Stepping assignments are made in the loop body before any other forms
are evaluated in the body.
The variable argument in iteration control clauses can be a destructuring list. A destructuring list is a tree whose non-nil atoms are variable names. See Section 6.1.1.7 (Destructuring).
The iteration control clauses for
, as
, and repeat
must precede any other loop clauses, except
initially
, with
, and named
,
since they establish variable bindings.
When iteration control clauses are
used in a loop
,
the corresponding
termination tests in the loop body are evaluated
before any other loop body code is executed.
If multiple iteration clauses are used to control iteration, variable
initialization and stepping1 occur sequentially by default.
The and
construct can be used to connect two or more
iteration clauses when sequential binding and
stepping1 are not necessary.
The iteration behavior of clauses joined by and
is analogous to the behavior of the macro do
with
respect to do*
.
The for
and as
clauses iterate by using one or more local
loop variables that are initialized to some value and that
can be modified or stepped1 after each iteration.
For these clauses, iteration terminates when a local
variable reaches some supplied value or when some other loop clause
terminates iteration.
At each iteration, variables can be
stepped1 by an increment or a decrement
or can be assigned a new value by the evaluation of a form).
Destructuring can be used to assign
values to variables during iteration.
The for
and as
keywords are synonyms; they can be used
interchangeably. There are seven syntactic formats for these constructs.
In each syntactic format, the type of
var can be supplied by the optional type-spec
argument. If var is a destructuring list, the type
supplied by the type-spec argument must appropriately match
the elements of the list.
By convention, for
introduces new iterations and as
introduces iterations that depend on a previous iteration specification.
In the for-as-arithmetic subclause, the for
or as
construct iterates from the value supplied by
form1 to the value supplied by form2 in increments or
decrements denoted by form3. Each
expression is evaluated only once and must evaluate to a number.
The variable var is bound to the value of
form1 in the first iteration and is stepped1
by the value of form3 in each succeeding iteration, or by 1 if form3 is not provided. The following loop keywords serve as valid prepositions within this syntax. At least one of the prepositions must be used; and at most one from each line may be used in a single subclause.
from | downfrom | upfrom
to | downto | upto | below | above
by
The prepositional phrases in each subclause may appear in any order.
For example, either “from x by y
” or “by y from x
” is permitted.
However, because left-to-right order of evaluation is preserved,
the effects will be different in the case of side effects.
Consider:
(let ((x 1)) (loop for i from x by (incf x) to 10 collect i)) → (1 3 5 7 9) (let ((x 1)) (loop for i by (incf x) from x to 10 collect i)) → (2 4 6 8 10)
The descriptions of the prepositions follow:
from
The loop keyword from
specifies the value from which
stepping1 begins, as supplied by form1.
Stepping1 is incremental by default. If
decremental stepping1 is desired,
the preposition downto
or above
must be used with form2. For incremental
stepping1, the default from
value is 0.
downfrom, upfrom
The loop keyword downfrom
indicates that the variable var is decreased in decrements
supplied by form3; the loop keyword upfrom
indicates that
var is increased in increments supplied by form3.
to
The loop keyword to
marks the end value
for stepping1 supplied in form2.
Stepping1 is incremental by default.
If decremental stepping1 is desired,
the preposition downfrom
must be used with form1,
or else the preposition downto
or above
should be used instead
of to
with form2.
downto, upto
The loop keyword downto
specifies decremental stepping;
the loop keyword upto
specifies incremental stepping.
In both cases, the amount of change on each step is specified by form3,
and the loop
terminates when the variable var passes
the value of form2.
Since there is no default for form1 in decremental stepping1,
a form1 value must be supplied (using from
or downfrom
)
when downto
is supplied.
below, above
The loop keywords below
and above
are analogous to
upto
and downto
respectively. These keywords stop
iteration just before the value of the variable var reaches the value
supplied by form2; the end value of form2 is not included.
Since there is no default for form1 in decremental stepping1,
a form1 value must be supplied (using from
or downfrom
)
when above
is supplied.
by
The loop keyword by
marks the increment or decrement supplied by
form3. The value of form3 can be any
positive
number.
The default value is 1.
In an iteration control clause, the for
or as
construct
causes termination when the supplied limit is reached. That is,
iteration continues until the value var is stepped to the
exclusive or inclusive limit supplied by form2. The range is
exclusive if form3 increases or decreases var
to the value of form2 without reaching that value; the loop
keywords below
and above
provide exclusive limits. An
inclusive limit allows var to attain the value of
form2; to
, downto
, and upto
provide inclusive
limits.
;; Print some numbers. (loop for i from 1 to 3 do (print i)) ▷ 1 ▷ 2 ▷ 3 → NIL ;; Print every third number. (loop for i from 10 downto 1 by 3 do (print i)) ▷ 10 ▷ 7 ▷ 4 ▷ 1 → NIL ;; Step incrementally from the default starting value. (loop for i below 3 do (print i)) ▷ 0 ▷ 1 ▷ 2 → NIL
In the for-as-in-list subclause,
the for
or as
construct iterates over the contents of a
list. It checks for
the end of the list as if by using endp
.
The variable var is bound to the successive elements of
the list in form1 before each
iteration. At the end of each iteration, the function step-fun
is applied to the list; the default value for step-fun is
cdr
.
The loop keywords in
and by
serve as valid prepositions in
this syntax.
The for
or as
construct causes termination when the
end of the list is reached.
;; Print every item in a list. (loop for item in '(1 2 3) do (print item)) ▷ 1 ▷ 2 ▷ 3 → NIL ;; Print every other item in a list. (loop for item in '(1 2 3 4 5) by #'cddr do (print item)) ▷ 1 ▷ 3 ▷ 5 → NIL ;; Destructure a list, and sum the x values using fixnum arithmetic. (loop for (item . x) of-type (t . fixnum) in '((A . 1) (B . 2) (C . 3)) unless (eq item 'B) sum x) → 4
In the for-as-on-list subclause, the for
or as
construct iterates over
a list. It checks for the
end of the list as if by using atom
.
The variable var is bound to the successive tails of the
list in
form1. At the end of each iteration, the function step-fun
is applied to the list; the default value for step-fun is cdr
.
The loop keywords on
and by
serve as valid
prepositions in this syntax.
The for
or as
construct causes termination when the
end of the list is reached.
;; Collect successive tails of a list. (loop for sublist on '(a b c d) collect sublist) → ((A B C D) (B C D) (C D) (D)) ;; Print a list by using destructuring with the loop keyword ON. (loop for (item) on '(1 2 3) do (print item)) ▷ 1 ▷ 2 ▷ 3 → NIL
In the for-as-equals-then subclause
the for
or as
construct
initializes the variable var by setting it to the
result of evaluating form1 on the first iteration, then setting
it to the result of evaluating form2 on the second and
subsequent iterations. If form2 is omitted, the construct
uses form1 on the second and
subsequent iterations.
The loop keywords = and then
serve as valid prepositions
in this syntax.
This construct does not provide any termination tests.
;; Collect some numbers.
(loop for item = 1 then (+ item 10)
for iteration from 1 to 5
collect item)
→ (1 11 21 31 41)
In the for-as-across subclause the for
or as
construct binds the variable var to the value of
each element in the array vector.
The loop keyword across
marks the array vector; across
is used as a preposition in this syntax.
Iteration stops when there are no more elements in the supplied
array that can be referenced.
Some implementations might recognize a the
special form
in the vector form to produce more efficient code.
(loop for char across (the simple-string (find-message channel)) do (write-char char stream))
In the for-as-hash subclause
the for
or as
construct
iterates over the elements, keys, and values of a hash-table.
In this syntax, a compound preposition is used to designate access to a
hash table.
The variable var takes on the value of each hash key
or hash value in the supplied hash-table.
The following loop keywords serve as valid prepositions within this syntax:
being
The keyword being
introduces either the Loop schema
hash-key
or hash-value
.
each
, the
The loop keyword each
follows the loop keyword being
when hash-key
or
hash-value
is used. The loop keyword the
is used with
hash-keys
and hash-values
only for ease of reading.
This agreement isn't required.
hash-key
, hash-keys
These loop keywords access each key entry of the hash table. If
the name hash-value
is supplied in a using
construct with one
of these Loop schemas, the iteration can optionally access the keyed
value. The order in which the keys are accessed is undefined; empty
slots in the hash table are ignored.
hash-value
, hash-values
These loop keywords access each value entry of a
hash table. If
the name hash-key
is supplied in a using
construct with one of
these Loop schemas, the iteration can optionally access the key that
corresponds to the value. The order in which the keys are accessed is
undefined; empty slots in the hash table are ignored.
using
The loop keyword using
introduces
the optional key or the keyed value to
be accessed. It allows access to the hash key if iteration is over
the hash values, and the hash value if
iteration is over the hash keys.
in
, of
These loop prepositions introduce hash-table.
In effect
being
{each
| the
}
{hash-value
|
hash-values
|
hash-key
|
hash-keys
}
{in
| of
}
is a compound preposition.
Iteration stops when there are no more hash keys or hash values to be referenced in the supplied hash-table.
In the for-as-package subclause
the for
or as
construct
iterates over the symbols in a package.
In this syntax, a compound preposition is used to designate access to a
package.
The variable var takes on the value of each symbol
in the supplied package.
The following loop keywords serve as valid prepositions within this syntax:
being
The keyword being
introduces either the Loop schema
symbol
, present-symbol
, or external-symbol
.
each
, the
The loop keyword each
follows the loop keyword being
when symbol
,
present-symbol
, or external-symbol
is used.
The loop keyword the
is used with symbols
,
present-symbols
, and external-symbols
only for ease of reading.
This agreement isn't required.
present-symbol
, present-symbols
These Loop schemas iterate over the symbols
that are present in a package.
The package to be iterated over is supplied in the same way
that package arguments to find-package
are supplied.
If the package for the iteration is not supplied,
the current package is used.
If a package that does not exist is supplied,
an error of type package-error
is signaled.
symbol
, symbols
These Loop schemas iterate over symbols that are
accessible in a given package.
The package to be iterated over is supplied in the same way
that package arguments to find-package
are supplied.
If the package for the iteration is not supplied,
the current package is used.
If a package that does not exist is supplied,
an error of type package-error
is signaled.
external-symbol
, external-symbols
These Loop schemas iterate over the external symbols of a package.
The package to be iterated over is supplied in the same way
that package arguments to find-package
are supplied.
If the package for the iteration is not supplied,
the current package is used.
If a package that does not exist is supplied,
an error of type package-error
is signaled.
in
, of
These loop prepositions introduce package.
In effect
being
{each
| the
}
{symbol
|
symbols
|
present-symbol
|
present-symbols
|
external-symbol
|
external-symbols
}
{in
| of
}
is a compound preposition.
Iteration stops when there are no more symbols to be referenced in the supplied package.
(let ((*package* (make-package "TEST-PACKAGE-1")))
;; For effect, intern some symbols
(read-from-string "(THIS IS A TEST)")
(export (intern "THIS"))
(loop for x being each present-symbol of *package*
do (print x)))
▷ A
▷ TEST
▷ THIS
▷ IS
→ NIL
When a loop
form is executed, the local variables are bound and are
initialized to some value. These local variables exist until loop
iteration terminates, at which point they cease to exist.
Implicit variables are also established by iteration control clauses and the
into
preposition of accumulation clauses.
The with
construct initializes variables that are local to
a loop. The variables are initialized one time only.
If the optional type-spec argument is supplied for the variable
var, but there is no related expression to be evaluated, var
is initialized to an appropriate default value for its type.
For example, for the types t
, number
,
and float
,
the default values are nil
, 0
, and 0.0
respectively.
The consequences are undefined if a
type-spec argument is supplied for var if
the related expression returns a value that is not of the supplied
type.
By default, the with
construct initializes variables
sequentially; that is, one variable is assigned a value before the
next expression is evaluated. However, by using the loop keyword and
to join several with
clauses,
initializations can be forced to occur in parallel; that
is, all of the supplied
forms are evaluated, and the results are bound to the respective
variables simultaneously.
Sequential binding is used when it is desireable for the initialization of
some variables to depend on the values of previously bound variables.
For example, suppose the variables a
, b
, and c
are to be bound in sequence:
(loop with a = 1
with b = (+ a 2)
with c = (+ b 3)
return (list a b c))
→ (1 3 6)
The execution of the above loop
is equivalent to the execution of
the following code:
(block nil (let* ((a 1) (b (+ a 2)) (c (+ b 3))) (tagbody (next-loop (return (list a b c)) (go next-loop) end-loop))))
If the values of previously bound variables are not needed
for the initialization of other local variables, an
and
clause can be used to
specify that the bindings are to occur in parallel:
(loop with a = 1
and b = 2
and c = 3
return (list a b c))
→ (1 2 3)
The execution of the above loop is equivalent to the execution of the following code:
(block nil (let ((a 1) (b 2) (c 3)) (tagbody (next-loop (return (list a b c)) (go next-loop) end-loop))))
;; These bindings occur in sequence. (loop with a = 1 with b = (+ a 2) with c = (+ b 3) return (list a b c)) → (1 3 6) ;; These bindings occur in parallel. (setq a 5 b 10) → 10 (loop with a = 1 and b = (+ a 2) and c = (+ b 3) return (list a b c)) → (1 7 13) ;; This example shows a shorthand way to declare local variables ;; that are of different types. (loop with (a b c) of-type (float integer float) return (format nil "~A ~A ~A" a b c)) → "0.0 0 0.0" ;; This example shows a shorthand way to declare local variables ;; that are the same type. (loop with (a b c) of-type float return (format nil "~A ~A ~A" a b c)) → "0.0 0.0 0.0"