Destructuring Variables
One handy feature of **LOOP**
I haven’t mentioned yet is the ability to destructure list values assigned to loop variables. This lets you take apart the value of lists that would otherwise be assigned to a loop variable, similar to the way **DESTRUCTURING-BIND**
works but a bit less elaborate. Basically, you can replace any loop variable in a for
or with
clause with a tree of symbols, and the list value that would have been assigned to the simple variable will instead be destructured into variables named by the symbols in the tree. A simple example looks like this:
CL-USER> (loop for (a b) in '((1 2) (3 4) (5 6))
do (format t "a: ~a; b: ~a~%" a b))
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6
NIL
The tree can also include dotted lists, in which case the name after the dot acts like a **&rest**
parameter, being bound to a list containing any remaining elements of the list. This is particularly handy with for
/on
loops since the value is always a list. For instance, this **LOOP**
(which I used in Chapter 18 to emit a comma-delimited list):
(loop for cons on list
do (format t "~a" (car cons))
when (cdr cons) do (format t ", "))
could also be written like this:
(loop for (item . rest) on list
do (format t "~a" item)
when rest do (format t ", "))
If you want to ignore a value in the destructured list, you can use **NIL**
in place of a variable name.
(loop for (a nil) in '((1 2) (3 4) (5 6)) collect a) ==> (1 3 5)
If the destructuring list contains more variables than there are values in the list, the extra variables are set to **NIL**
, making all the variables essentially like **&optional**
parameters. There isn’t, however, any equivalent to **&key**
parameters.