3 ms·
I should write a nice long blog post on how to iterate in CL without using (full) LOOP. (I have no problem with the trivial CLtL1 form of LOOP.) There's DO, t
by ScottBurson 12y ago
I should write a nice long blog post on how to iterate in CL without using (full) LOOP. (I have no problem with the trivial CLtL1 form of LOOP.) There's DO, there's MAPCAR, there's REDUCE, there's REMOVE-IF-NOT and the like, and these days we often have the option of using tail recursion. I believe that different kinds of loops should be written with different constructs, as this gives the reader a clue up front about the nature of the loop. If you see a MAPCAR, for example, you can assume (well, you should be able to assume) that the iterations are independent; there is no data flow from one invocation of the mapped function to another, so the ordering of the input list(s) affects only the ordering of the result list, not its contents. Furthermore, any loop with that property should be written as a MAPCAR so the reader can tell that.
The point, of course, is that trying to create "one macro to rule them all" is already wrongheaded. There shouldn't be one universal iteration construct.
- Guthur 12y agoPersonally I think LOOP is a fantastic example of how great and terrible macros in Lisp can be. To be able to produce a syntax abstraction like LOOP within the language is an example of mind boggling power available (excuse my minor hyperbole). But conversely one should also take it as an equally valid example of where restraint in the use of such power should be diligently exercised.
- eru 12y ago> The point, of course, is that trying to create "one macro to rule them all" is already wrongheaded. There shouldn't be one universal iteration construct. Tail-calls fit the bill. (And you can build things like reduce on top of them as normal functions.)
- malisper 12y agoI agree with you to some degree. Higher order functions should be used wherever possible and there should be some alternatives to LOOP for the common cases such as iterating over a range of numbers. It is much easier to understand patterns when they are built into the language than when they are written out using LOOP. The thing is LOOP is very good at creating ad hoc kinds of loops. Say you are writing a loop to do password validation. Repeat at most N times and then lock the account or go through once a correct password is entered. That kind of iteration is too specific for pretty much any kind of looping construct besides LOOP. As I see it, LOOP is not about creating "one macro to rule them all", it's about creating a macro that's a catch-all. One that you can always use when nothing else quite describes what you want. I'm just thinking out loud.
- ScottBurson 12y agoI would probably use DO for the password validation example. It's strange to me that people think of DO as complicated; there is a little complexity there, to be sure, but much less than for LOOP. Once you understand that the inits and updates are done in parallel, and you get where the exit test goes, you've got it; there are no more rules to learn. I understand that LOOP seems simple in simple cases, but that simplicity is evidently deceptive, as attested by the comments I was replying to.
- malisper 12y agoMakes sense. It's just to me, as someone who knows LOOP that (loop repeat n thereis (valid (read-password)) finally (lock-account)) seems simpler than (do ((i 0 (+ i 1))) ((>= i n) (lock-account)) (when (valid (read-password)) (return t))) You are definitely right that loop is deceptively complex. In the code I gave, a reader would need to know that thereis skips the epilogue when terminating the loop (I would comment the code if it was going to be seen by others). I'm now finding it incredible how much lingo I used in the last sentence.
- sjolsen 12y ago>The point, of course, is that trying to create "one macro to rule them all" is already wrongheaded. There shouldn't be one universal iteration construct. I agree that MAPCAR et al. should be used when they're appropriate. They are, however, sometimes simply not, and it's important to be able to build code to handle those cases. You don't need LOOP for that, since you can always use TAGBODYs and GOs, but LOOP is almost certainly more appropriate, just as MAPCAR et al. are usually more appropriate than LOOP. In other words, yes, there should be a universal iteration construct; there just shouldn't be only a universal iteration construct. There's nothing wrong with having multiple tools at different abstraction levels for the same group of tasks, and I'd argue that it's usually a good thing.
- ScottBurson 12y agoI agree it's great to have multiple tools; and obviously at the low level there has to be something universal that everything else is implemented with, whether that's TAGBODY/GO, DO, or tail recursion. But I still think LOOP tries to be the solution to too many problems. Worse, it attempts to replace compositionality -- the rules of the language by which more complex expressions are built up from simpler ones -- with vocabulary. Oh well. I've made my case -- I'll shut up now :-)
- PuercoPop 12y agoDo you have a blog? I'd love to read that post if you write some day. Although I personally use loop and eschew other iteration constructs I see the point you are getting at, it communicates better the intent.