Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • > Lisp programs are often much more concise because macros let you abstract away recurring patterns and make them part of the language itself

    This is why Lisp never catches on. Each programmer invents their own ad-hoc, undocumented, barely working language in the form of those macros. The same thing happens in other languages with macros (like C and assembler).

  • I've had some of the same ideas, I would love a full macro system on a dependently typed language. My stab at it earlier in January was not quite the right thing, but I do think this is the way. Weirdly enough concision is even more important in LLM context than in regular human context.
  • For LLMs, less code means fewer tokens, and tokens are what you pay for so you spend less on development.

    I don't think that's strictly true.

    What you need is for your LLM to be able to understand enough context to be able to make a change with as few token as possible, so if your code isn't expressive enough or if it has a tendrils calling lots of different functions/methods all over the place, then you'll have to give it much more code (context) than if you've got nice encapsulated modules that don't depend on other parts.

    The design of your architecture (probably?) has a greater impact on token use in a large app than the language it's written in. Although, obviously, languages lend themselves to particular architectures so it's correlated.

  • Lots of comments praising LLM's understanding of Common Lisp macros. I've seen them break badly at the macros-writing-macros level. I saw a current frontier model get so disoriented by one (a simple one!), it created something that expanded into a "(let (((".

    (That's an impossible count (3) of parentheses on the RHS—like a six-fingered hand).

  • I think half the article talks about why CL is good because it can resume from an exception, and half the article talks about why DSLs are good.

    I think others have pointed out that most modern scripting languages can halt at exceptions without unwinding the stack. Python & Node both support this with core tooling.

    As for DSLs, they constrain the LLM which generally helps with code quality. However why implement your DSL in the unconstrained chaos of CL? You can write DSLs in Rust which gives you static typing, a borrow checker, and clippy.

  • > because writing code used to be the slow part

    I don't understand how people have that stated as a fact. Coding was never the slow part. Neither pre-llm, nor now. How it needs to be done is software engineering. And that corresponds now to the "thinking" part of llms, so unless you are making the llm "think in lisp" its not useful. How would that even work. training data to be completely in lisp ?

    > Lisp programs are often much more concise because macros let you abstract away recurring patterns and make them part of the language itself

    functions ?

    > So the bigger the program gets, the bigger the difference. In my own experience the apps I've built in Common Lisp end up about six to seven times shorter than the Python versions

    By that logic writing code in this concept language made up completely of symbols would take you even further ( https://github.com/artpar/guage ) but in practice it doesnt because llms arent trained to that extent on this.

  • I have similar experiences in Clojure. I use Pi and created an extension which teaches the LLM how to start a JVM with a Clojure nREPL listening in it. Added a tool which lets the agent evaluate any Clojure form inside the JVM. Sprinkled the setup with clj-reload and now the agent is using the nREPL as if it were its second nature.

    What I like most is how fast testing goes: it modifies test code on disk, asks clj-reload to reload all affected namespaces, then reruns the tests. It's also fun to see how it verifies its assumptions by evaluating short programs through the nREPL.

    I asked it to organize the various subsystems inside my playground repo into Integrant systems and make it possible for me to say things like "restart the http subsystem".

    It also understands shadow-cljs: I replicated the necessary parts of the shadow CLI tooling in Clojure; now I can compile, watch and serve any number of CLJS apps located in various namespaces from inside the same JVM. There is no need to touch the command line any more: I just instruct the agent to start a particular CLJS app and it's there.

  • I feel like everyone has some sort of justification for why their pet language is now the best because LLMs can work in it better for a bunch of reasons.

    Javascript/Python is the best because there's so much code out there that the LLMs can train on, and LLMs can write lots of tests to make sure everything is correct. There's nothing to compile, so the LLM can iterate quickly.

    Rust is the best because the LLM gets great feedback from the compiler because of its strong type system, and it can deal with the borrow checker for you.

    Go is the best because it's a simpler language with a decent type system, and the LLM can reason about that well, and will never forget to check an `err` return. The compiler is fast, so the LLM can iterate quickly.

    I could write similar praise for C, C++, Java...

    At this point I don't think any language is the best "because LLMs". I think there are quite a few languages that LLMs are probably not good at, but you have lots of choices if you want something they are good at.

Explore Birbla archives