3 ms·
As I said LOOP is designed such that names, local variables, local iteration variables are all defined INSIDE the LOOP, such that LOOP can process them and that
by lispm 4y ago
As I said LOOP is designed such that names, local variables, local iteration variables are all defined INSIDE the LOOP, such that LOOP can process them and that they are all using the LOOP syntax.
(loop with a = ...) maybe equivalent to (let ((a ...)) (loop ...))
but
(let ((a ...)) ... (loop ...) ...) is not equivalent to (loop with a = ...)
The difference is that in the latter it is not clear to the Lisp developer that A is meant as a LOOP local variable.
That's a design choice, not bad design.
Historically LOOP was named FOR and was only a tiny part of CLISP (Conversational Lisp) in Interlisp. There CLISP had a different syntax than normal Lisp, including iteration, binding, infix operations, etc. The idea of such a LOOP macro was then brought to Maclisp, ZetaLisp and, eventually, ANSI Common Lisp.
- lisper 4y ago> The difference is that in the latter it is not clear to the Lisp developer that A is meant as a LOOP local variable. That's because in the latter example, A is NOT a loop-local variable. If you write: (let ((a ...)) (some-form)) then it is clear that a is local to (some-form) regardless of what (some-form) actually is. If you write: (let ((a ...)) (some-form) (some-other-form)) then obviously it is not clear whether a is local to (some-form) or (some-other-form) or both. But so what? If it matters that this be clear, just don't put multiple forms inside the body of your LET, and then it is clear. You don't need to design a whole new language to solve this non-existent problem. > That's a design choice, not bad design. It introduces a lot of additional complexity, including a syntax that is radically different from anything else in the language, and confers very little benefit. If that is not diagnostic of a bad design I can't imagine what would be.
- lispm 4y ago> You don't need to design a whole new language to solve this non-existent problem. The designers thought that a whole new language would be useful. One may disagree with it. I would have preferred something like the ITERATE macro, but it has exactly the same idea of ENCLOSING all of these LOOP clauses, but with more parentheses. (iterate (with a = 1) (incf a) (when (> a 10) (return a))) is (loop with a = 1 do (incf a) when (> a 10) return a) If one cares about radically different syntax then you wouldn't use LOOP at all. (loop for i in l do (print i)) is equivalent to (dolist (i l) (print i)) which is equivalent to something with a LET/TAGBODY... construct. Why not just use the latter? Maybe its design choices made it practical enough?
- lisper 4y ago> The designers thought that a whole new language would be useful. Yes, obviously they thought this. They were wrong. > ITERATE Iterate is a slight improvement over loop because at least it doesn't require a whole new editor mode to format it properly, but simply adding parens to loop doesn't really fix it. The lack of parens is the least of LOOP's problems. I'll give you two more examples of problems with loop. This is still nowhere near an exhaustive list. 1. There is no way to iterate over a sequence. You can iterate over a list, or you can iterate over a vector, but you cannot efficiently iterate over something that is either a list or a vector. You have to write something like: (typecase seq (cons (loop for item in seq ...)) (vector (loop for item across seq ...))) which forces you to duplicate all of the LOOP code twice. Worse, you have to actually duplicate all the code represented by the elipses. You can't abstract it away in a function or a macro. 2. LOOP is not extensible. There are a lot of things I might want to be able to loop over, like streams, but I can't. There are a lot of control constructs I might want to embed in a loop, like with-open-file, but I can't. Instead, I have to resort to manually writing idioms like: (loop with stream = (open path) with eof-marker = (gensym "EOF") for thing = (read stream nil eof-marker) while (not (eq thing eof-marker)) ... finally (close stream)) and again, because of the non-orthogonal syntax, I can't abstract all that away in to a macro either. I have to write it all out manually every single time I want to iterate over the contents of a file. (And after all that it doesn't even do the right thing if the loop code signals a condition!)
- mojifwisi 4y agoIterate doesn't have either of these problems, so I don't see how it's just a "slight improvement". > There is no way to iterate over a sequence. With iterate, you'd do: (iter (for item in-sequence seq) ...) > LOOP is not extensible. But iterate can be extended with DEFMACRO-CLAUSE.[1] I think that's why iterate added the parentheses in the first place. [1]: https://iterate.common-lisp.dev/doc/Rolling-Your-Own.html https://iterate.common-lisp.dev/doc/Rolling-Your-Own.html
- lisper 4y ago