Štar: an iteration construct for Common Lisp
tfeb.org
tfeb.org
Ironically enough, once my use of it advanced enough, I found myself writing producing forms which are just a restricted form of Loop invocation - Series turns out to compile down to Loop. It's just that I (and others, apparently) find Series expressions more pleasant to deal with than Loop expressions.
[1] https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html#...
[2] http://funcall.blogspot.com/2022/07/series-tips-and-tricks.h...
>> Seemingly, the intended way to use the LOOP facility is to just "guess" a way to express an iteration and see if it works. If it doesn't you can either look up the specifics ...
Since then, I do just guess at the syntax and it strangely does what I want most of the time.
It seems that a library like this has a lot to prove because a) it doesn't provide a new capability, b) it adds a project dependency, and c) creates yet another way to do a standard task. If you really don't like the loop macro, you probably don't need much persuading, but I would have liked to have seen more discussion on the these trade-offs.
Only css is done this way... but not even intentionally
https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node235.html
The grammar for what's accepted by Loop is well specified, but the results also read very clearly. Once you learn a few of them, you start to understand how the rest would be written and can guess, but the design is not that you would guess.
Perl was famously that way. It's great for the initial write but not so good for maintenance.
Learning to use perl -properly- is a whole other barrel of monkeys though.
(it does have the advantage that it's very easy to spot code written by a confused perl programmer, whereas I've experienced a number of unfortunate events where python code initially looked fine but turn out to be logically utterly confused; this is not a complaint about python, though it does darkly amuse me)
Either way I think they were looking for a recursive solution. Oh well, they still invited me to lunch, though.
Anecdote: In almost 20 years of CL usage, I've never needed an extensible iteration construct. I also find 'loop' a lot more readable than 'iterate' [1], another fad that has come and gone.
I know that there are projects like Lem[2] that try to build some kind of editor (Emacs-like, I guess) on top of CL, which made me wonder if we would have a CL-based Emacs today if it would have been standardized by the time and if this would have been a better choice than creating a custom dialect.
[1]: https://www.gnu.org/software/emacs/manual/html_node/cl/ (C-h R "cl" in Emacs)
The question is what makes this species.
For example see https://www.finseth.com/craft/#c10.1
It's the command set (key bindings, extended commands, ...), buffers with modes and minor modes, the user interface for buffers, marks, the "cursor", extensibility, ...
For example in a typical Emacs the "cursor" / current mark is always visible, even in GUI versions. This is very different from other editors, where the current cursor can be non visible.
Basically there are a lot of similarities between the early Emacs editors (EMACS, EINE/ZWEI/ZMACS, Multics Emacs, ... and others).
Does LEM try to be similar to an EMACS editor or is it only emulating one on demand?
GNU Emacs use might also think of Emacs Lisp as an extension language, a GUI version, menubars with menus, self-documentation, ...
It is not clear to me why the marketing for lem is "a Lisp IDE" when it clearly is "an emacs written in Common Lisp"
For what it's worth, I quit using it since it broke if you ever used the CL function `count` inside an iterate construct. Reportedly it was fixed, but it's still failing to work correctly using the Quicklisp version (just installed CL on and setup QL since it's a new laptop, so it shouldn't be pulling an old version). It was fun for a while, but having to remember "Oh yeah, don't use count" every time I reached for it for something natural was annoying and not worth bothering with.
Methodology (yes, I could've stayed in Lisp, but I started by awking systems.txt...):
(with-open-file (*standard-output* #p"deps.txt" :direction :output)
(iter
(for system in (ql:provided-systems t))
(for name = (ql::name system))
(format t "~a ~a~%" (length (ql:who-depends-on name)) name)))
$ sort -h deps.txt | tail
200 uiop
201 iterate
206 split-sequence
274 closer-mop
344 cl-glfw-opengl-core
350 bordeaux-threads
387 fiveam
391 cffi
408 cl-ppcre
1006 alexandria> iteration and value accumulation are orthogonal problems which should be solved by orthogonal constructs
This is also covered to an extent by "Why Functional Programming Matters" in the discussion of laziness: https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.p...
For a direct comparison of combining this syntax with "accumulation" into a lazy sequence, see Clojure's `for` macro:
* Syntactic sugar for nested loops is welcome!
* I would have preferred a comparison with https://github.com/Shinmera/for/, as it's nearer in concept than loop/iterate.
* Eschewing collection is a mistake in my opinion. Yes, you can do your own with (let ((ret)) (for ... (push it ret)) (nreverse ret)), but it'll be verbose.
As other said, it's a very Scheme-y vision of looping, which has simplicity/purity/explicitness advantages but lacks in pragmatism. Personally, I firmly stay in the iterate team, even with its issues.
I also find it a bit fragile for iterator implementations to use 2 functions, rather than a single function returning `value | unique-end-of-iterator-sentinel` (there are at least 3 obvious ways to lay this out such that there are no values an iterator cannot produce).
is there more?
what is the next thing?
In addition it knows how to ask another question: is there any information I can use to make asking the first two questions faster?
```This approach sounds so good. Focus on what is needed to solve the main task. Don't do less, but please don't do more. And... Do Not Assume.
> is there more?
> what is the next thing?
> This approach sounds so good.
Does it? I think separating the checking for presence of a next value (hasNext) from retrieving that value (next) isn’t the best idea, and most performant implementations will secretly already do the latter when asked the former, but then have to add an additional check in the “what is the next thing?” method in case there isn’t any.
That’s doing extra work in cases where the program only is interested in whether there are more items, but that rarely happens, doesn’t it?
Yes, good compilers can often combine the two through inlining and the like, but why make the compiler do extra work if you also could have “what is the next thing, if any?” as the sole method? (That’s more or less what IEnumerator.MoveNext does in C# (https://learn.microsoft.com/en-us/dotnet/api/system.collecti...))
> (loop for x in l while (numberp x) do ...)
> Instead you write
> (for ((x (in-list l)))
> (unless (numberp x) (final))
> ...)
While loop has arcane grammar and can be hard to write correctly, it will be read many more times and so I think is preferable to the latter.
Personally I use LOOP because it is built in. But generally I prefer something like ITERATE, which is similar powerful but fits better into the host language (-> Common Lisp).