Because this is a macro, if you have to debug or step, you get to do so through the expanded code. This is usually not fun. But at least it's a memory-safe language, so it's not the hell of fixing C++ template bugs.
I can understand that debugging expanded code is not fun.
On the other hand, LOOP allows to naturally express iteration patterns that can be error-prone with other languages: you hardly produce off-by-one bugs contrary to hand-crafted loops.
It does not lead to the LOOP macro. The LOOP macro is a special approach for an embedded language for iteration. It's coming from on an older idea from Interlisp: Conversational LISP.
LOOP provides quite a bit more than a `FOR` statement: various forms of iteration and stepping, value accumulation, termination, flow control, ...
It's basically a special style of embedded DSL for it iteration. If one wants to implement such a thing, there is only a way through macros in Lisp. There are lots of iteration macros for Lisp - most have a slightly simplified grammar, though not necessarily less features (see the ITERATE macro, which has more features than LOOP plus more parentheses).
In other language this would have to be implemented in the language's internal implementation.
> Because this is a macro, ...
Similar to DO, DO*, DOTIMES, DOLIST, ... which are all macros in Common Lisp.
> if you have to debug or step, you get to do so through the expanded code.
like so much in Common Lisp and like so much in Lisp in general. Source translations are quite typical for this language family. It makes debugging quite a bit more difficult.
For an alternative to this look at SERIES, which is also implemented with macros, but looks and works completely different.
Generally stepping is difficult in Lisp. If you would want to step through a call to a MAP function, you will step through its implementation and repeated calls to a closure argument, which might not be pretty.
The main thing which makes ITERATE more idiomatic in Lisp from a syntactic point of view is this: ITERATE groups clauses as sublists.
Other than that the ITERATE approach is very similar to LOOP.
(iterate (for el in num-list)
(when (> el 3)
(collect el)))
vs.
(loop for el in num-list
when (> el 3)
collect el)
As you can see from the above example, ITERATE has more parentheses... which from a Lisp point of view makes sense. But for this typical iteration example it looks almost the same, otherwise.
ITERATE has also quite some more capabilities than LOOP, for example it supports accumulation of results from nested loops.
Mesa and Smalltalk, yes. Interlisp, no. A LISP command line was not the right answer. Storing programs as LISP images was not a great idea. And Do-What-I-Mean was really an error corrector for Warren Teitelbaum's typing errors. I once typed "EDIT" when in the wrong mode, and DWIM printed "=EXIT" and threw me out of Interlisp without saving.
My serious LISP work was done in Franz LISP, which had a more UNIX-like compile and run interface.
Warren Teitelman originally wrote DWIM to fix his typos and spelling
errors, so it was somewhat idiosyncratic to his style, and would often make
hash of anyone else's typos if they were stylistically different. Some
victims of DWIM thus claimed that the acronym stood for ?Damn Warren?s
Infernal Machine!'.
In one notorious incident, Warren added a DWIM feature to the command
interpreter used at Xerox PARC. One day another hacker there typed delete
*$ to free up some disk space. (The editor there named backup files by
appending $ to the original file name, so he was trying to delete any
backup files left over from old editing sessions.) It happened that there
weren't any editor backup files, so DWIM helpfully reported "*$ not found,
assuming you meant 'delete *'". It then started to delete all the files on
the disk! The hacker managed to stop it with a {Vulcan nerve pinch} after
only a half dozen or so files were lost.
The disgruntled victim later said he had been sorely tempted to go to
Warren's office, tie Warren down in his chair in front of his workstation,
and then type delete *$ twice.
And you don't really have to debug the expanded code (unless you want to). It's perfectly possible to retain the original unexpanded source locations for debugging in a properly designed Lisp.
> Because this is a macro, if you have to debug or step, you get to do so through the expanded code. This is usually not fun. But at least it's a memory-safe language, so it's not the hell of fixing C++ template bugs.
So wrong...
(loop for x from i to 10 do magic (foo))
Compound form expected, but found MAGIC.
Current LOOP context: DO MAGIC (FOO).
[Condition of type CCL::SIMPLE-PROGRAM-ERROR]
The C2 wiki presents (as usually) a very uneducated view about Lisp. I am not going to rip apart the details but whenever you read something about Lisp on the C2 wiki please keep in mind that Lisp is not their usual cup of coffee really.
So if you see something like "Lisp macros could be easily replaced with a magic Ruby block lotion and are just lambdas + syntax", just because nobody on C2 argues with it doesn't mean its not completely ignorant and wrong.
While you can't replace all macros with blocks, I think there's an interesting argument in there about doing some things done with macros using blocks, and that it has the advantage that a function accepting a block can be passed around in ways a macro can't be.
No. Smalltalk called these blocks, and Ruby does too.
BTW a lambda expression and a closure are not the same thing. A lambda expression evaluates to a closure, just as an expression like "(make-instance 'foo)" (or "new Foo()" for non-Lispers) evaluates to an instance. The former, in each case, is a syntactic entity, something you can write in your program; the latter is an object inside the machine.
27 comments
[ 3.7 ms ] story [ 385 ms ] threadhttp://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/l...
This essentially adds a FOR statement to LISP, using 1495 lines of LISP macros. Here's its manual: http://www.ai.sri.com/pkarp/loop.html
Because this is a macro, if you have to debug or step, you get to do so through the expanded code. This is usually not fun. But at least it's a memory-safe language, so it's not the hell of fixing C++ template bugs.
On the other hand, LOOP allows to naturally express iteration patterns that can be error-prone with other languages: you hardly produce off-by-one bugs contrary to hand-crafted loops.
See the Appendix of the Iterate manual for a comparison of looping constructs in CL: http://common-lisp.net/project/iterate/doc/Don_0027t-Loop-It....
http://www.softwarepreservation.org/projects/LISP/interlisp/...
> This essentially adds a FOR statement to LISP
LOOP provides quite a bit more than a `FOR` statement: various forms of iteration and stepping, value accumulation, termination, flow control, ...
It's basically a special style of embedded DSL for it iteration. If one wants to implement such a thing, there is only a way through macros in Lisp. There are lots of iteration macros for Lisp - most have a slightly simplified grammar, though not necessarily less features (see the ITERATE macro, which has more features than LOOP plus more parentheses).
In other language this would have to be implemented in the language's internal implementation.
> Because this is a macro, ...
Similar to DO, DO*, DOTIMES, DOLIST, ... which are all macros in Common Lisp.
> if you have to debug or step, you get to do so through the expanded code.
like so much in Common Lisp and like so much in Lisp in general. Source translations are quite typical for this language family. It makes debugging quite a bit more difficult.
For an alternative to this look at SERIES, which is also implemented with macros, but looks and works completely different.
http://lispm.de/docs/cltl2/clm/node347.html#SECTION003400000...
Generally stepping is difficult in Lisp. If you would want to step through a call to a MAP function, you will step through its implementation and repeated calls to a closure argument, which might not be pretty.
A more Lisp-idiomatic approach to iteration, though not so far from LOOP, is ITERATE.
http://www.common-lisp.net/project/iterate/doc/Don_0027t-Loo...
Other than that the ITERATE approach is very similar to LOOP.
vs. As you can see from the above example, ITERATE has more parentheses... which from a Lisp point of view makes sense. But for this typical iteration example it looks almost the same, otherwise.ITERATE has also quite some more capabilities than LOOP, for example it supports accumulation of results from nested loops.
My serious LISP work was done in Franz LISP, which had a more UNIX-like compile and run interface.
I only have experience with Smalltalk (VisualWorks back then).
The Lisp and Mesa/Cedar environments is only due to my archeologist work from programming languages and environments.
And you don't really have to debug the expanded code (unless you want to). It's perfectly possible to retain the original unexpanded source locations for debugging in a properly designed Lisp.
So wrong...
So if you see something like "Lisp macros could be easily replaced with a magic Ruby block lotion and are just lambdas + syntax", just because nobody on C2 argues with it doesn't mean its not completely ignorant and wrong.
Edit: "Arrrrrr, nasty Lisp-folk, if they weren't just programmers who know Lisp, arrrr."
Then YOU lecture him.
> opinions are ten-a-penny on the internet.
Including your own, it seems.
Besides, your comment's wrong, and people should know that.
No, don't expect me to say way.
BTW a lambda expression and a closure are not the same thing. A lambda expression evaluates to a closure, just as an expression like "(make-instance 'foo)" (or "new Foo()" for non-Lispers) evaluates to an instance. The former, in each case, is a syntactic entity, something you can write in your program; the latter is an object inside the machine.
B: Look what you can do with not-macros.
A: Great.
;)