Книга: Practical Common Lisp
Conditional Execution
Conditional Execution
Because a do
clause can contain arbitrary Lisp forms, you can use any Lisp expressions you want, including control constructs such as IF
and WHEN
. So, the following is one way to write a loop that prints only the even numbers between one and ten:
(loop for i from 1 to 10 do (when (evenp i) (print i)))
However, sometimes you'll want conditional control at the level of loop clauses. For instance, suppose you wanted to sum only the even numbers between one and ten using a summing
clause. You couldn't write such a loop with a do
clause because there'd be no way to "call" the sum i
in the middle of a regular Lisp form. In cases like this, you need to use one of LOOP
's own conditional expressions like this:
(loop for i from 1 to 10 when (evenp i) sum i) ==> 30
provides three conditional constructs, and they all follow this basic pattern:
LOOP
conditional test-form loop-clause
The conditional can be if
, when
, or unless
. The test-form is any regular Lisp form, and loop-clause can be a value accumulation clause (count
, collect
, and so on), an unconditional execution clause, or another conditional execution clause. Multiple loop clauses can be attached to a single conditional by joining them with and
.
As an extra bit of syntactic sugar, within the first loop clause, after the test form, you can use the variable it
to refer to the value returned by the test form. For instance, the following loop collects the non-NIL
values found in some-hash
when looking up the keys in some-list
:
(loop for key in some-list when (gethash key some-hash) collect it)
A conditional clause is executed each time through the loop. An if
or when
clause executes its loop-clause if test-form evaluates to true. An unless
reverses the test, executing loop-clause only when test-form is NIL
. Unlike their Common Lisp namesakes, LOOP
's if
and when
are merely synonyms—there's no difference in their behavior.
All three conditional clauses can also take an else
branch, which is followed by another loop clause or multiple clauses joined by and
. When conditional clauses are nested, the set of clauses connected to an inner conditional clause can be closed with the word end
. The end
is optional when not needed to disambiguate a nested conditional—the end of a conditional clause will be inferred from the end of the loop or the start of another clause not joined by and
.
The following rather silly loop demonstrates the various forms of LOOP
conditionals. The update-analysis
function will be called each time through the loop with the latest values of the various variables accumulated by the clauses within the conditionals.
(loop for i from 1 to 100
if (evenp i)
minimize i into min-even and
maximize i into max-even and
unless (zerop (mod i 4))
sum i into even-not-fours-total
end
and sum i into even-total
else
minimize i into min-odd and
maximize i into max-odd and
when (zerop (mod i 5))
sum i into fives-total
end
and sum i into odd-total
do (update-analysis min-even
max-even
min-odd
max-odd
even-total
odd-total
fives-total
even-not-fours-total))
- Conditional Statements
- Unconditional Execution
- Conditional Formatting
- Conditionals and Looping
- 2.3.6. Execution Contexts
- 7.2.4. Execution Context
- Configuring Remote Login and Execution
- UUCP Transfers and Remote Execution
- Command Execution
- 14.3.2 Pseudo versus True Concurrent Execution
- Условная Инструкция (Conditional)
- *FEATURES* and Read-Time Conditionalization