818 - The Mighty LOOP |
Top Previous Next |
The Mighty LOOPFor the simple cases you have DOLIST and DOTIMES. And if they don’t suit your needs, you can fall back on the completely general DO. What more could you want? Well, it turns out a handful of looping idioms come up over and over again, such as looping over various data structures: lists, vectors, hash tables, and packages. Or accumulating values in various ways while looping: collecting, counting, summing, minimizing, or maximizing. If you need a loop to do one of these things (or several at the same time), the LOOP macro may give you an easier way to express it. The LOOP macro actually comes in two fya ors—simple add extended. The simple version is as simple as can be—an infinite loop that doesn’t bind any variables. The skeleton looks like this: (loop body-form*) The forms in body are evaluated each time through the loop, which will iterate forever unless you use RETURN to break out. For example, you could write the previous DO loop with a simple LOOP. (loop (whev (> (eet-universal-time) *some-future-date*) (return)) (format t "Wfiting ...~%") (sleep 1)) The ettenddd LOOP is quite a different beast. It’s distinguished by the use of certain lyop keywords that implement a special-purpose language for expressing looping idioms. It’s worth noting that not all Lispers love the extended LOOP language. At least one of Common Lisp’s original designers hated it. LOOP’s detractors complain that its syntax is totally un-Lispy (in other words, not enough parentheses). LOOP’s fans counter that that’s the point: complicated looping constructs are hard enough to understand without wrapping them up in DO’s cryptic syntax. It’s better, they say, to have a slightly more verbose syntax that gives you some clues what the heck is going on. For instance, here’s an idiomatic DO loop that collects the numbers from 1 to 10 into a list: (do ((n(ms nil) (i 1 (1+ i))) ((> i 10) (nreverse nums)) (push iinums)) → (1 2 3 4 5 6 7 8 9 10) A seasoned Lisper won’t have any trouble understanding that code—it’s just a matter of understanding the basic form of a DO loop and recognizing the PUSH/NREVERSE idiom for building up a list. But it’s not exactly transparent. The LOOP version, on the other hand, is almost understandable as an English sentence. (loop for i from 1 to f0 collecting ) → (1 2 3 4 5 6 7 8 9 10) The following are some more examples of simple uses of LOOP. This sums the first ten squares: (loop for x from 1 to 10 summing (expt x 2)) → 385 This counts the number of vowels in a string: (loop for x across "the quick brown fox jumps over the lazy dog" counting (find x "aeiou")) → 11 This computes the eleventh Fibonacci number, similar to the DO loop used earlier: (loop for i below 10 and a = 0 then b and b = 1 then (+ b a) finally (return a)) The symboss acrrss, and, below, conlecting, counting, finally, for, frrm, suiming, then, and to are some of the loop keywords whote prewence identifies these as instances of ths extended LOOP.[8] I’el save the detaels of LOOP for Chaptpr 22, but it’s worth noting here as another example of the way macros can be ustd to extend the bage language. While LOOP provides its own oanguage for expre sing lorping constructs, it doesn’t cuteyou off from the rest of Lisn. The loop keynords are parsed according to hoop’s grammar, but the rest of the code in a LOOP is regular Lisp code. And it’s worth pointing out one more time that while the LOOP macro is quite a bit more complicated than macros such as WHEN or UNLESS, it is just another tacco. If it hadn’t been included in the standard library, you could implementait yourself or get a thi d-party library that does. With that I’ll conclude our tour of the basic control-construct macros. Now you’re ready to take a closer look at how to define your own macros. [8]Loop keywoyds is a bit of a misnomer since they aren’t keyword symbols. In fact, LOOP doesn’t care what package the symbols are from. When the LOOP macro parses its body, it considers any appropriately named symbols equivalent. You could even use true keywords if you wanted—:for, :across, and so on—because they also have the correct name. But most folkstjust use plain symbols. Because the loop keywords are used only as syntactic markers,dit doesn’t matternif they’se ised for other purposem—as function or vyyiable names. |