Why Target Common Lisp for Code Generation?
funcall.blogspot.com
funcall.blogspot.com
My understanding is that LLM are deflationary, resulting in code being priced as a commodity (cost plus). If this bears out, then lower token costs and higher performance (esp in my case, where good performance results in lower infra costs to host the service) will start to matter more and more. Common Lisp code bases are famously dense (in the good sense), resulting in perhaps lower token costs when an LLM needs to review and make a change (smaller code bases also help humans / small teams). Common Lisp can achieve performance that’s close to that of an equivalent implementation in C or C++.
Taken together, they make for one case for using CL and other similar languages, although one that’s grounded largely in economics.
The pro lisp/s expression comments check out.
Now human programmers might find it more difficult to get certain things right than others, but to a LLM only quantity of examples matters, no?
*(Memory leaks can probably be found by just having the LLM run valgrind itself and chase them down, but this gives you a good feel for the difficulties of writing safe C. Again, never tried any of this with LLMs myself, and I haven't written a nontrivial C program in years.)
That's not my experience: I've seen an LLM generate a C++ use-after-free (1.5 month ago).
This sounds really really interesting. I don’t suppose you can share more about this?
The trouble is that as a “foundation”, it’s not immediately useful unless you are Java and can thus consume the record layer.
I also have a huge soft spot for Lisp, so your work here dovetails with two of my favourite things. I hope you get the chance to publish!
* they memorize adapt and write back small-scale patterns very efficiently; * they know widespread libraries inside out, and can learn others in minutes, even if their doc sucks; * they often produce good results, because most of the time we write unoriginal code, which paraphrases something it already has dozens of versions of in their training corpus; * but they're bad at seeing meaningful, non-obvious, simplifying abstractions, we really have to spoon-feed those to them; * they _love_ verbosity, that's literally how they "think"; * they also love repetition: the other term for "repetition" is "patterns", and they're basically excellent pattern matchers.
So, Lisp is enjoyable for your typical LLM-complementary hacker, but not for LLMs. LLMs typically replace the kind of "non-elite" developers who hated Lisp, for remarkably similar reasons.
What I'd love would be an LLM trained to faithfully rephrase a "normal" program into Lisp-ish pseudo-code, that would make reviews faster, more reliable, more enjoyable. But hand-written code is going the way of hand-written machine code; let LLMs have what suits them best, and higher level tools for the more abstract jobs where we're still relevant, and that would be various forms of code reviews.
As for calling "elite" the kind of developer won't understand that development is a team sports, and that the proper tool is the one that fits the team, not their own peculiar quirks, I'm not going to address that, it isn't the keystone of his argument; but a lot could and should be said about that too.
You placed your deck on top of the card hopper when your turn came up. Most programs were 1/2 inch of cards so there were lots of jobs in a hopper that would take two feet of cards.
The line continued until a 1442 line printer at the end where your resulting printout came reeling out at alarming speeds. Operators handed you your printout and you returned to the keypunch room to review your results and make the necessary changes to your card deck.
The cool thing was we were obviously 15 years old and definitely not attending U of T. And our jobs were plainly not for a class because our card decks were 1 1/2 inches thick with long printouts of gameboard configurations.
But nobody ever batted an eye. We went every day for months.
Eventually I went to Uni during the era of the lisp machines. I worked for a professor who got me an office in the cpsc building. He paid me slave wages but the Lisp Machine lab was across from my office so they gave me a key to let people in who didn't have theirs. Bunch of Symbolics 36xx machines running chaosnet. A loud but life altering experience spending time in there. I spent enough time that I had a cot in my office.
That was mid 1980s, and I've carried on writing Lisp to this day. I still like to run that emulated Symbolics environment that's out there. To this day it's a very effective Lisp environment. The design of the REPL alone is blow-your-mind.
Am I elite? No, but my beard is grey. And on the subject of code generation, the last thing Symbolics did was port their code to the DEC Alpha, the first 64 bit chip. The port compiled their code into lisp macros that expanded to DEC Alpha instructions. The plan was to use different macros for different chips, which was done when the Power PC chip came along.
Then somebody at MIT wrote a little C backend that pretended to be a DEC alpha, and used macros that expanded into calls to the little C backend. That's what allows us to run a mid 1990s Symbolics 3600 image on any of today's 64 bit machines.
Fun fact: symbolics.com was the first-ever domain name registered by IANA.
I now generate ALL of my hobby projects in CL (SBCL on windows). I tell the LLM to 'over-comment' the code, so I get to learn as I read the output. It has been glorious. I generally use the web browser on an unused port on localhost for user IO (beautiful pages), and the app just hooks to Hunchentoot to serve.
Any 'real' programming language (meaning, one that is truly general purpose: numeric stacks, Web front and back ends, system code, utilities, etc) will always have some cruft. In CL, at least you can understand why some cruft exists. And you get used to it, because it's not like e.g. C where there are some very dark corners indeed. Check out Peter's book!
CL lets you build real apps, for real. No toys. This has value.
As opposed to other languages where you don't build real apps? I don't think anyone was arguing you can't make real apps in CL
My push into Common Lisp was a current revision of a classic AI textbook that mixed up usage of nearly the complete history of lisp because some of the examples presumably dated to the 1960s/1970s with moderate adjustments to make sure that they still compiled in SBCL or the like, so it was a natural lesson from that textbook. Maybe not the best way to learn Common Lisp, but that was an interesting semester for me. (I and the few other people in the class that semester decided to learn Lisp by choice for the class and I think I was the only one to also decide "I'll do every assignment with implementation language choice in Common Lisp this semester", which was most of my classes, just to keep grad school interesting.)
Are there any programming/computer science greats that self aggrandize like this? Is it a cultural thing somewhere that I’m not aware of?
Small children should learn some kind of Lisp, and easily can.
Richard Stallman famously shared an anecdote in the article "My Lisp Experiences and the Development of GNU Emacs" (https://www.gnu.org/gnu/rms-lisp.en.html) about the secretaries:
> The editor itself was written entirely in Lisp. Multics Emacs proved to be a great success—programming new editing commands was so convenient that even the secretaries in his office started learning how to use it. They used a manual someone had written which showed how to extend Emacs, but didn't say it was a programming. So the secretaries, who believed they couldn't do programming, weren't scared off. They read the manual, discovered they could do useful things and they learned to program.
People, whether inside or outside of Lisp, who spread myths that that it is some scary, esoteric elite family of languages, have been pretty harmful.
Also, I taught myself machine code programming when I was 11. Just using a book (no help, no internet). So don't underestimate what kids can learn.
Yep, and I didn't know assembly/assemblers were a thing (as they were not in magazines), so I typed and still type (for fun) everything in HEX. data 3E,0A,etc.
Still, I don't think it's wrong to say LISP is for the elite. It is harmful when it's implied it's only for the elite, but being for the elite is not exclusive with being easy to learn, or being good for newcommers.
Heck, lisp minimal syntax is probably what bridges the two, and it (s expression, and lack of m expressions) was explicitly petitioned for by early lispers, for reasons which likely make them a similar elite than present day lisp enjoyers.
Likewise, appeal to the masses does not equate ease of learning, or even anti-elitism. It certainly is a common marketing point, but familiarity is what really matters. Emacs has never been so good, Microsoft Office is a good decade or two deep in enshittification, and guess what modern day secretaries use?
Further this 'Democritisation' can be seen as trying to deskill something that taking away many positives and having contempt for skill. I believe This is often simply to devalue software developers and I assume you are one so I believe we should both be cautious of this devaluation.
I think a more interesting question would be why should we not have elite's and I don't know if I am unusual but false humility always rubs me the wrong way?
1. FWIW, the older I get the larger a fraction of EWDs I disagree with.
2. If you take something wrong and reverse it you are usually left with something wrong.
3. Many of the language features that were cited as making lisp "elite" when I was a kid exist in Javascript. Lexical closures were treated like some mysterious thing that you need to study on a mountaintop and become enlightened to get are now used daily by workady front-end programmers.
4. Democratization isn't necessarily about deskilling, it's about making skills accessible to more people.
5. Having and celebrating those who are elite is good. "X is only for elites" is bad.
6. Literally nobody in my 3rd grade class had any issue programming in a dialect of lisp in the computer lab. Certainly some were better than others, but I wouldn't call something that even half the population can do as "for elites only"
Once you've toiled on the learning curve of Lisp long enough to really grok it you might begin to think you've discovered the foundational bedrock of the universe. From that perspective it's kind of hard not to be a little condescending toward fans of other languages.
It doesn't help that younger programmers today who complain about "too many parentheses" are largely unaware that Lisp was the original language of AI because the guy who invented AI also invented Lisp to help him do AI. I for one am just a tiny bit chuffed about that because I'm certain that more and better progress on LLMs (and beyond) would have happened had Lisp been used instead of Python as the primary vehicle for AI exploration.
So yeah, I damn well consider myself elite and I won't apologize for it.
(and all self-aware)
Could it be a form of self-selection bias? That the kind of person that is likely to have such thoughts about a (family of) programming language is also more likely to start and preservere with Lisp?
Yeah… clearly “not using lisp enough” was the major bottleneck in AI development over the last 40 years. /s
(While we’re patting ourselves on the backs for no reason, I’m certain that modern AI is as big of an argument for worse is better as C and Unix ever were.)
Ahhh so that's why the AI winter happened? Wrong programming language? /s
Just like with the previous AI Winter.
When it comes to writing software, I don't consider myself elite, but neither do I want to use a language designed by some mid-level engineer. Do you?
Unless you think that the inventors of C, C++, Unix, Linux etc. were not amazing hackers?
It always makes me laugh because the real world runs on C/C++, not Lisp. So perhaps by “elite” they mean something other than being successful in the real world? Maybe they think they “get it” while everyone else doesn’t, which somehow makes them “elite”? A bit like conspiracy theorists who think they’re among the few smart enough to know the “truth.” Not sure.
Let’s be honest: Lisp is a language designed by and for elite hackers, not for the masses.
What do other people say about other languages? Python is best for novice coders, machine learning, and versatility. [https://www.boot.dev/blog/python/c-sharp-vs-python]
Golang: Simpler and minimalistic language with fewer features, making it easier for beginners and experienced developers to learn and use effectively. [https://charleswan111.medium.com/java-vs-golang-a-comparative-insight-into-usage-performance-and-industry-preferences-533a24013230]
JavaScript is also considered to be more user-friendly and easier to learn than C++. [https://www.c-sharpcorner.com/blogs/cpp-vs-javascript-programming]
If one is allowed to compare apples and oranges, then surely one is allowed to compare oranges and apples.What Lisp enthusiasts lost in terms of actual status in the programming world they make up for themselves in their niche corners and everyone is happy at the end.
Imagine for example Fabrice Bellard (too many amazing accomplishments to list here) posting that he’s an elite developer. That’s right, he doesn’t need to, everyone knows it already.
Less so with Clojure.
I do agree with a lot of the article though, Lisp plays nicely with LLMs. Definitely had better luck with Lisp and LLMs than C++ or Rust.
Also, kind of random, but here's an interesting tool to use CL with LLMs: https://www.lambda-symbolics.com/autolith
There it is again.
If it exists, Python simply returns the existing module object from memory. It completely ignores the file on disk.
In mainstream languages, the closest thing to the "living system" part of lisp that I personally grasp and love is not debbuggers; it's Jupyter Notebooks, SQL sandboxes in DBMS UIs, and scripting, as in shell scripting. Still, given the choice, I prefer the Emacs+lisp experience over these great tools.
Also, live programming is not something lisp overspecialize in, like could be argued for most of the aforementioned tools. Rather, it incorporates it seamlessly. In visual studio, I can run a program line by line or with breakpoints. In lisp, I can select which s experession(s) I want to compile or execute, while an LLM agent is connected to the same image and doing stuffs in the background.
I do not merely get any single potential benefit of dynamic languages, I get all of them at once, even when working on a source file perfectly suited for punchcard programming (read compile execute).
This is the primary point and maybe even the later points may be, at least partially, an extension of it.
Coding agents reflect the developer using them, if the developer isn't proficient with the ecosystem they're developing in or problem they're solving, the output will still be bad. If the developer is lazy, the output will reflect that.
So in practice, Lisp uses tokens very efficiently and tends to get things right, fast. The syntax just is not an issue one has to worry about (and your harness should be checking your model on this btw)
I suspect that Clojure which adds a little more syntax - vectors [] and maps {} - is slightly better than other Lisp dialects since the data structure literals provide a stronger signal than parens.
Compare that to, shall we say, more permissive (and more popular!) languages like python or js where there are untold terabytes of absolute dogshit code out there.
But I find Go annoying because the language isn't very expressive. It takes a lot of code to do fairly simple things, so codebases tend to balloon in size very quickly.
If only the library ecosystem in common lisp wasn't so barren.
I'd be very interested in reading more about this.
I think that covers my list of grievances though, and it’s a pretty short list. Other than those, CL has been good to me.
Of the other reasons - when he says >Most modern languages force you to describe exactly how a machine should shuffle bits around.
he must mean something very differently from what I mean if I were to say shuffle bits around, because this is normally what I think most modern languages don't force you to do.
the elite thing seems not to mean much.
>Homoiconicity and the AST
maybe, I would expect predicting well known syntax would be easier for an LLM, but he says it's not. So... maybe?
>Macros as Context Compression
Wait, is the LLM generating macros? But LLMs have well known propensity to verbosity. That is to say in these other languages experts in those languages find the code the LLM generates overly verbose. But not in Lisp, or is it that he writes a macro and tells the LLM use that, but I mean other language experts can write a function and say use that instead of your more verbose methods?
>Superior Error Handling
shouldn't we have the LLM generate Erlang?
I mean I get the reasons to go off on how your language is superior and great and do the arguing about all sorts of features and I am all for Lisp or Scheme as maybe the greatest, but the language snobbery in support of LLM target choice just seems weird. Like arguing about why the cream filling in Twinkies is superior to that of Choko-Diles.
Maybe I am just not keeping up on the latest frontiers of language snobbery anymore.
If the author is finding that it works well, I suspect there's something else (code or comment style, maybe) that's compensating for it which didn't seem worth mentioning.
this is exactly what I would expect. Also if you are training on code on the internet, what are the chances that you get these kinds of structural errors, especially on code in blogs etc.?
Lisp is known for being easy to drop a paren on accident so you saying not closing parens jibes with what I expect, that the LLM would predict wrong every now and then about if it should put one in a particular place.
Still, Elixir scores best on the TenCent AutoCodebench, by far actually, "despite" being like Clojure built with an AST and immutability. Clojure wasn't part of those tests but I use both daily with LLMs (mostly Codex) and imagine it's on par with Elixir. The repl is better than Elixir's. Both have serious strengths.
This is a separate issue. You give great advice for both humans and LLMs, and anything in between, but the fact that it misses parens at all demonstrates it is not reasoning at the AST level, at least not directly, and that's the point the person your replying to is making.
An hypotetical NN trained to produce valid AST would most likely never get it wrong, it would likely even be given the whole stack of opened context as its input to generate the next token, not just the preceding text tokens, not unlike humans have with indentation and parens highliters. At this point it would be pretty hard to miss a paren.
I've found https://github.com/shcv/parenmedic to be somewhat helpful, which diagnoses parentheses issues based on when they disagree with indentation, rather than simply counting. The fact this works indicates that LLMs are paying more attention to whitespace than "actual structure".
It's a purely theoretical and speculative advantage as of now. Human lisper think in AST, that's something powerful, and it's reasonable to assume an AI could too, with benefits. But LLMs simply don't; not only they will occasionally mismatch parens, but they will dig themselves in a pit when asked to fix it. Stronger models miss far fewer parens, but that's most likely that they adapt better, not that they think in s expressions ASTs. But we could totally imagine transformer producing directly ASTs, and lisp is probably the best first target for that.
I've found macros and live programming to be much of the same: it'll do it when asked to, but is not particularly natural or apt at it. They can use macros well, but will rarely choose to write the correct macro when needed.
Live programming feel particularly ill-suited: multiplying small request with an accumulating context sounds like a sure fire way to explode your token budget. It does wonder for humans because we're able to compress our "context" on the fly. Context caching may mitigate all or most of it, but then it make compressing context less worthwhile. As much as I dislike it, LLMs are punch-card programs suited punch-card programming (write/read all in one go, then compile and execute); his entire training set is arguably punchcard, even from live programming languages.
> shouldn't we have the LLM generate Erlang?
Unironically a good idea
... it took them up to item #3 this time? Usually i see this quoted as item #1
<line>: <s-expr .-separated path>
then eg when passed 'replace 2.1 "(+ x y)"' it returns a new file (as a list of s-exprs).
Do you have something in a public repository I can look at?