Common Lisp the Language, 2nd Edition
Next: Variable
Initializations Up: Loop
Previous: End-Test
Control
Accumulating values during iteration and returning them from a loop is
often useful. Some of these accumulations occur so frequently that
special loop clauses have been developed to handle them.
The loop keywords append
, appending
,
collect
, collecting
, nconc
, and
nconcing
designate clauses that accumulate values in lists
and return them.
The loop keywords count
, counting
,
maximize
, maximizing
, minimize
,
minimizing
, sum
, and summing
designate clauses that accumulate and return numerical values. [There is
no semantic difference between the ``ing’’ keywords and their
non-``ing’’ counterparts. They are provided purely for the sake of
stylistic diversity among users. I happen to prefer the non-``ing’’
forms-when I use loop
at all.-GLS]
The loop preposition into
can be used to name the
variable used to hold partial accumulations. The variable is bound as if
by the loop construct with
(see section 26.9). If into
is
used, the construct does not provide a default return value; however,
the variable is available for use in any finally
clause.
You can combine value-returning accumulation clauses in a loop if all
the clauses accumulate the same type of data object. By default, the
Loop Facility returns only one value; thus, the data objects collected
by multiple accumulation clauses as return values must have compatible
types. For example, since both the collect
and
append
constructs accumulate objects into a list that is
returned from a loop, you can combine them safely.
;;; Collect every name and the kids in one list by using
;;; COLLECT and APPEND.
(loop for name in '(fred sue alice joe june)
for kids in '((bob ken) () () (kris sunshine) ())
collect name
append kids)
=> (FRED BOB KEN SUE ALICE JOE KRIS SUNSHINE JUNE)
[In the preceding example, note that the items accumulated by the
collect
and append
clauses are interleaved in
the result list, according to the order in which the clauses were
executed.-GLS]
Multiple clauses that do not accumulate the same type of data object
can coexist in a loop only if each clause accumulates its values into a
different user-specified variable. Any number of values can be returned
from a loop if you use the Common Lisp function values
, as
the next example shows:
;;; Count and collect names and ages.
(loop for name in '(fred sue alice joe june)
as age in '(22 26 19 20 10)
append (list name age) into name-and-age-list
count name into name-count
sum age into total-age
finally
(return (values (round total-age name-count)
name-and-age-list)))
=> 19 and (FRED 22 SUE 26 ALICE 19 JOE 20 JUNE 10)
[Loop Clause]
collect
expr [into
var]
collecting
expr [into
var]
During each iteration, these constructs collect the value of the specified expression into a list. When iteration terminates, the list is returned.
The argument var is set to the list of collected values; if
var is specified, the loop does not return the final list
automatically. If var is not specified, it is equivalent to
specifying an internal name for var and returning its value in
a finally
clause. The var argument is bound as if
by the construct with
. You cannot specify a data type for
var; it must be of type list
.
Examples:
;;; Collect all the symbols in a list.
(loop for i in '(bird 3 4 turtle (1 . 4) horse cat)
when (symbolp i) collect i)
=> (BIRD TURTLE HORSE CAT)
;;; Collect and return odd numbers.
(loop for i from 1 to 10
if (oddp i) collect i)
=> (1 3 5 7 9)
;;; Collect items into local variable, but don't return them.
(loop for i in '(a b c d) by #'cddr
collect i into my-list
finally (print my-list)) `;Prints 1 line
(A C)
=> NIL
[Loop Clause]
append
expr [into
var]
appending
expr [into
var]
nconc
expr [into
var]
nconcing
expr [into
var]
These constructs are similar to collect
except that the
values of the specified expression must be lists.
The append
keyword causes its list values to be
concatenated into a single list, as if they were arguments to the Common
Lisp function append
.
The nconc
keyword causes its list values to be
concatenated into a single list, as if they were arguments to the Common
Lisp function nconc
. Note that the nconc
keyword destructively modifies its argument lists.
The argument var is set to the list of concatenated values;
if you specify var, the loop does not return the final list
automatically. The var argument is bound as if by the construct
with
. You cannot specify a data type for var; it
must be of type list
.
Examples:
;;; Use APPEND to concatenate some sublists.
(loop for x in '((a) (b) ((c)))
append x)
=> (A B (C))
;;; NCONC some sublists together. Note that only lists
;;; made by the call to LIST are modified.
(loop for i upfrom 0
as x in '(a b (c))
nconc (if (evenp i) (list x) '()))
=> (A (C))
[Loop Clause]
count
expr [into
var]
[type-spec]
counting
expr [into
var]
[type-spec]
The count
construct counts the number of times that the
specified expression has a non-nil
value.
The argument var accumulates the number of occurrences; if
var is specified, the loop does not return the final count
automatically. The var argument is bound as if by the construct
with
.
If into
var is used, the optional
type-spec argument specifies a data type for var. If
there is no into
variable, the optional type-spec
argument applies to the internal variable that is keeping the count. In
either case it is an error to specify a non-numeric data type. The
default type is implementation-dependent, but it must be a subtype of
(or integer float)
.
Example:
(loop for i in '(a b nil c nil d e)
count i)
=> 5
[Loop Clause]
sum
expr [into
var]
[type-spec]
summing
expr [into
var]
[type-spec]
The sum
construct forms a cumulative sum of the values
of the specified expression at each iteration.
The argument var is used to accumulate the sum; if
var is specified, the loop does not return the final sum
automatically. The var argument is bound as if by the construct
with
.
If into
var is used, the optional
type-spec argument specifies a data type for var. If
there is no into
variable, the optional type-spec
argument applies to the internal variable that is keeping the sum. In
either case it is an error to specify a non-numeric data type. The
default type is implementation-dependent, but it must be a subtype of
number
.
Examples:
;;; Sum the elements of a list.
(loop for i fixnum in '(1 2 3 4 5)
sum i)
=> 15
;;; Sum a function of elements of a list.
(setq series
'(1.2 4.3 5.7))
=> (1.2 4.3 5.7)
(loop for v in series
sum (* 2.0 v))
=> 22.4
[Loop Clause]
maximize
expr [into
var]
[type-spec]
maximizing
expr [into
var]
[type-spec]
minimize
expr [into
var]
[type-spec]
minimizing
expr [into
var]
[type-spec]
The maximize
construct compares the value of the
specified expression obtained during the first iteration with values
obtained in successive iterations. The maximum value encountered is
determined and returned. If the loop never executes the body, the
returned value is not meaningful.
The minimize
construct is similar to
maximize
; it determines and returns the minimum value.
The argument var accumulates the maximum or minimum value;
if var is specified, the loop does not return the maximum or
minimum automatically. The var argument is bound as if by the
construct with
.
If into
var is used, the optional
type-spec argument specifies a data type for var. If
there is no into
variable, the optional type-spec
argument applies to the internal variable that is keeping the
intermediate result. In either case it is an error to specify a
non-numeric data type. The default type is implementation-dependent, but
it must be a subtype of (or integer float)
.
Examples:
(loop for i in '(2 1 5 3 4)
maximize i)
=> 5
(loop for i in '(2 1 5 3 4)
minimize i)
=> 1
;;; In this example, FIXNUM applies to the internal
;;; variable that holds the maximum value.
(setq series '(1.2 4.3 5.7))
=> (1.2 4.3 5.7)
(loop for v in series
maximize (round v) fixnum)
=> 6
;;; In this example, FIXNUM applies to the variable RESULT.
(loop for v float in series
minimize (round v) into result fixnum
finally (return result))
=> 1
Next: Variable
Initializations Up: Loop
Previous: End-Test
Control
AI.Repository@cs.cmu.edu