I keep flipping between Clojure and CL. I like functional programming, so I really like the workflow of Clojure, but the more-interactive nature of CL is incredibly appealing and I like that it doesn’t put so many constraints on you. I love how you can inspect everything and dig into the core of the language so easily and the interactive debugger is insanely cool.
But I just find it so painful to use, all the functions have strange names, docs are shaky especially for libraries, and I just keep bouncing off. I am going to try Advent of Code in CL this year, but I always get tied up in knots with the data manipulation, especially how you seemingly need to use the loop macro for basically everything since there aren’t that many data structure manipulation methods in the standard library. Hashes are also pretty awkward to work with compared to Java Maps or clojure maps.
Also, I can’t shake the feeling that doing all my data manipulation with linked lists is horribly slow, especially since they aren’t lazily evaluated.
ASDF and the package system is like no other language I’ve ever used, which always ties me in knots, too.
Does anyone have any tips? Is there something I’m missing regarding data manipulation, or is it more a matter of breaking through the pain barrier with practice?
“all the functions have strange names”, very strange. Most names in CL standard are self-explanatory, such as DEF*, DEFINE-, MAKE-. Others have well-known history or legends or rules. Few are difficult, such as PRIN1 (still have meaning, think about PRIN2)
“progn” is a good example. This has far more sensible names in other Lisps. But I’m mostly talking about data structure access methods. They are so inconsistent - at lead the access library improves on this though.
Well known histories/legends/rules don’t count, I’m talking about new developer experience. But I get your point, they have a sort of consistency to them
I definitely prefer scheme’s
begin
, butprogn
does have a consistent logic behind its name.(progn expr1 expr2 ... exprN)
returns the result ofexprN
, and(prog1 expr1 expr2 ... exprN)
returns the result ofexpr1
. There’s also aprog2
which returns the obvious.It does? Strange. Because the spec says:
:)
PROG1, PROG2, …, PROGN very ruleful. N reminds you returning the last value. On the other hand, PROG means “Program Feature”. PROGN is really a good name.
“They are so inconsistent”. Different data structures have different operations. Specific operators are accurate and efficient. The costs are that you have to remember/command all these operators. A similarity is the equality operator. EQUALP is most generic. But you mostly use EQ, EQL, CHAR=, STRING=, etc. for specific objects.
Common Lisp is a bit like an onion. There are different layers of language and the inner layers date back to the first Lisp implementation from 1958. It’s grown over decades.
A beginner is now confronted with history and inconsistencies. On the positive side a goal was not to throw away useful older applications or libraries, they could be ported over the different generations of Lisp. Same for the book. If you read a CL introduction from the mid 80s it’s still mostly valid, but lacks newer stuff. It’s also the implementations: some SBCL code may date back to the early 80s, with Spice Lisp, which was started even before Common Lisp existed.
At that time PROG was a widely used control structure for imperative programming. PROG1, PROG2 and PROGN were a bit similar and indicate in the name which result is returned.
You walk in a street, where some house are a few hundred years old and some are relatively new, using different building styles.