On Sunday, 30 July 2017 02:02:17 UTC+2,
christop...@gmail.com wrote:
> Hi guys, so I'm new to Common Lisp, having migrated to CL from Racket, and I have a question about looping constructs.
Nice to meet you!
>
> ## The LOOP macro
>
> LOOP is super complex, but also insanely powerful and (from a passing comment read somewhere else) quite efficient. There is no analogue in other languages for the mighty LOOP.
The thing is, LOOP isn't anything strange. It's just strange for Lisp. Take a look at Python - you have LOOP in there, although as part of language - we use macros to extend it instead.
In for loop, the basic things to remember are:
(loop repeat N do ...) - when you need to iterate N times and don't bother with keeping index of current element.
(loop for x in list do ...) - when you want to iterate over a list
(loop for x across vec do ...) - when you want to iterate over a vector
(loop ... with something = something-else ...) - when you want to declare the local variables.
(loop ... collecting ...) - when you want to create a list.
This is enough for most cases. Now one more useful thing to remember is that you can use clauses more than once. This is especially useful in for loop:
(loop for x across some-vector
for i from 0 do ...)
Now you are able to track both the element of the vector(it's x), as well as its index (it's i). It's equivalent to something like "for x,i in enumerate(some-list)" in Python.
I often use LOOP for the purpose above, or when the code gets a little bit more complex. Also, LOOP creates an unnamed block, so you can return from it.
There's also ITERATE, which is kind of like Loop, but extensible and a bit different.
> ## MAPCAR and friends
> They are sometimes wasteful because they lack a way to return early, and there are many variants for various things, instead of a one-stop shop.
when you MAP, then by definition, you apply the function to *every* element, so it's not wasteful. mapcar is most useful when you have some function that you want to apply to each element from list. MAP is useful in the same way, but works on any sequence. If you want to add 1 to each element of list, (mapcar #'1+ list) is the best code imho - concise, precise, readable.
> ## DOLIST and friends
>
> This set of macros are what I'm using most often right now, mostly because their analogues in Racket are the idiomatic looping constructs in Racket and I feel most comfortable with them. They seem to be a midpoint between LOOP and MAPCAR.
This is the one I use the least. It's just that most of the time I can either use mapcar or loop, and they are usually more readable/concise. It's a bit easier to control what LOOP returns than DOLIST imho.
Anyway, tl;dr is that they are all used, although I probably use DOLIST the least in my code(actually hardly ever).
- Loop is more imperative - more likely to be used in imperative program.
- Mapcar is more functional - more likely to be used in functional program.
- Mapcar is superior when you want to apply function to the list. If you want to combine functions, use Alexandria library.
- Mapcar and other MAPs, if used as they should be(order does not matter), can be easily parallelised by using lparallel. You just add one letter before each mapping construct and it now works on threads.
- dolist/dotimes etc. are often replaced with LOOP.
Use whatever you like best, but these are my thought on the topic. Ultimately, if the code works, then it does not matter which of these has been used.