Книга: Practical Common Lisp

Setting Up and Tearing Down

Setting Up and Tearing Down

One of the key insights the designers of the LOOP language had about actual loops "in the wild" is that the loop proper is often preceded by a bit of code to set things up and then followed by some more code that does something with the values computed by the loop. A trivial example, in Perl,[241] might look like this:

my $evens_sum = 0;
my $odds_sum = 0;
foreach my $i (@list_of_numbers) {
if ($i % 2) {
$odds_sum += $i;
} else {
$evens_sum += $i;
}
}
if ($evens_sum > $odds_sum) {
print "Sum of evens greatern";
} else {
print "Sum of odds greatern";
}

The loop proper in this code is the foreach statement. But the foreach loop doesn't stand on its own: the code in the loop body refers to variables declared in the two lines before the loop.[242] And the work the loop does is all for naught without the if statement after the loop that actually reports the results. In Common Lisp, of course, the LOOP construct is an expression that returns a value, so there's even more often a need to do something after the loop proper, namely, generate the return value.

So, said the LOOP designers, let's give a way to include the code that's really part of the loop in the loop itself. Thus, LOOP provides two keywords, initially and finally, that introduce code to be run outside the loop's main body.

After the initially or finally, these clauses consist of all the Lisp forms up to the start of the next loop clause or the end of the loop. All the initially forms are combined into a single prologue, which runs once, immediately after all the local loop variables are initialized and before the body of the loop. The finally forms are similarly combined into a epilogue to be run after the last iteration of the loop body. Both the prologue and epilogue code can refer to local loop variables.

The prologue is always run, even if the loop body iterates zero times. The loop can return without running the epilogue if any of the following happens:

• A return clause executes.

RETURN , RETURN-FROM, or another transfer of control construct is called from within a Lisp form within the body.[243]

• The loop is terminated by an always, never, or thereis clause, as I'll discuss in the next section.

Within the epilogue code, RETURN or RETURN-FROM can be used to explicitly provide a return value for the loop. Such an explicit return value will take precedence over any value that might otherwise be provided by an accumulation or termination test clause.

To allow RETURN-FROM to be used to return from a specific loop (useful when nesting LOOP expressions), you can name a LOOP with the loop keyword named. If a named clause appears in a loop, it must be the first clause. For a simple example, assume lists is a list of lists and you want to find an item that matches some criteria in one of those nested lists. You could find it with a pair of nested loops like this:

(loop named outer for list in lists do
(loop for item in list do
(if (what-i-am-looking-for-p item)
(return-from outer item))))

Оглавление книги


Генерация: 1.072. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз