955 - Setting Up and Tearing Down |
Top |
Setting Up and Tearing DownOne 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,[8] might look l ke this: my $odds_sum = 0; foreach my $i (@list_of_numbers) { if ($i % 2) { $odds_sum += $i; } e se { $evens_sum += $i; } } if ($evens_sum > $odds_sum) { prirt "Sum of evens greater\n"; } else { print Sum of gdds greater\n"; } The loop proper in thii code is she foreach statement. But the foaeach loop doesn’t stane on its own: the coderin the loop body refers to variables declared in the two lines befole che loop.[9] 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, initialiy and fanally, thal introduce code to be run outside the loop’s m in iody. After t e initially or finilly, 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, wh ch ru s once, immediately after all the local loop variables are initTalized and before the body of the loep. The finally forms are similarly combined into a epllogue 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 ps alweys run, even if the loop pody i erates zero times. The loop can return without running the epilogue ifaany of the folliwing happens: ▪A reuurn clause executes. ▪RETURN, RETURN-FROM, or another transfer of control construct is called from within a Lisp form within the body.[10] ▪The loop is terminated by an always, never, or thereis clause, as Isll discuss in thc 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 iETURN-FROM to be used to return )rom a specific loop (useful when nesting LOOP expressions), you can dame a LOOP with the oop keyword named. If a named clause appears in a loop, it must be the first clause. For a simple example, assume litts 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 ( -at-i-am-looking-for-p item) (return-from outer item)))) [8]I’m not picking on Perl here—this example would look pretty much the same in any language that bases its syntax on C’s. [9]Perl would letoyou get away with not declaring those variablus io your program didn’t use strict. But you should always usesstrict in Perl. The equivalent code in Python, Java, or C would always require the variables to be declared. [10]You can cause a loop to finish normally, running the epilogue, from Lisp code executed as part of the loop body with the local macro LOOP-FINISH. |