u/lispm
-
2points
- 27points
-
38points
Clozure CL: arm64 preview release (github.com)
- 44points
lispm
lispm
Claude Fable 5.1 and Opus 5.5 don't struggle at all with Lisp code. Actually they are quite good for debugging, porting and even for writing large amounts of new code. For the latter a bit of steering is needed, but then the results are quite good.
lispm
It better had been written all in SBCL, then.
lispm
The term vs. the mechanism. A Franz Lisp manual from 1980 describes "foreign function" calling. The term "foreign function interface" is for example used in Maple documentation in 1984. I would think that the mechanisms got important especially in the context of running Lisp (or similar) on C based operating systems, where one would want to use C libraries. Calling functions from other languages sure would be a problem which appeared earlier.
It got popular in Common Lisp, because many Common Lisps had to interface with C libraries in some way, especially if they were partly (or completely) implemented in C. This was complicated by the need to have managed memory (the Lisp heap) and manually managed memory (the C side). A FFI then would also be a user feature, where a programmer had ways to write their own calls to foreign functions. But the mechanism (and the name) is older than Common Lisp.
The mechanism:
https://mads.si.edu/mads/id/NMAH-AC0196_gris720521
In May of 1968, external functions were introduced into SNOBOL IV with the help of Howard Strauss, who was on Internship assignment internally in Bell Laboratories. SNOBOL III had external functions. They went under the name of machine language functions. This was an addition to SNOBOL IV to make it possible to extend the language during execution by loading and linking functions written in other languages, most specifically assembly language and FORTRAN to extend the SNOBOL IV system.
SNOBOL4: external functions for SNOBOL4. (1968)
Maclisp on Multics (1970s), calling PL/1.
Franz Lisp (1980).
lispm
SBCL 2.6.8
``` * (mapcan (constantly 1) (list 'a 'b) '( 11 22 33) )
debugger invoked on a TYPE-ERROR @80031A6308 in thread
<THREAD tid=259 "main thread" RUNNING {80086E06F3}>:
The value 1 is not of type LIST when binding LIST ```
lispm
I find it still unstable. Even more the GUI part. But it is a good sign of life...
lispm
Yes, that was very cool. That was your and the other maintainers work on SBCL.
lispm
This is not useful.
It matches my experience using it. You can read that as a joint experience report.
Though, I don't think the dialect-confusion is actually much of a problem in practice - at least from what I have seen. Parentheses mismatches happen occasionally, which then is additionally addressed by a special s-expression structure editor and other checks. I, myself, also use tools (editor, compiler, ...) to help write correctly indented/balanced code - without that I would also make more errors.
Thus that's the point of what is written above: here the LLM got a full set of interactive tooling for CL and is using it for interactive development with Common Lisp. The result is a typical experience of a long-running interactive development session in a running application and its software&development stack.
lispm
Just to be sure, it was my understanding that SBCL always compiled to native code, no bytecode generated. As such, a core dump is not portable among platforms. Is that not the case?
SBCL is usually natively compiled -> not portable across architectures&OS combinations. SBCL does have an optional Lisp interpreter, but without byte code machinery.
A way around that (taken by Java JVM, Smalltalk, ...), is platform independent byte-code interpretation plus an optional just in time compiler (JIT compilation) for that byte code. That's uncommon in Common Lisp. A Common Lisp implementation for the JVM will support that, though. There are other byte code engines for Lisp (ECL has one, CLISP has one (IIRC), ... Plus, there are emulators for Lisp architectures ("Lisp Machines"), which typically can emulate the Lisp CPU -> thus their images usually work on different underlying architecture/OS combinations.
...Clojure...
was originally designed as a hosted language, reusing a host eco-system (JVM, .net, JavaScript, ...). Thus the JVM-based Clojure inherits all of the JVM underneath (byte code format, byte-code interpreter, byte code loader, JIT compiler, ...) , plus its eco-system.
There are other implementations of programming languages on the JVM, which do that to a similar degree. ABCL, though, additionally tries to be a full ANSI Common Lisp, which is a language specified independent of an underlying system / hardware.
SBCL, as a fork of CMU CL, is a typical natively compiling Lisp, with its own Lisp-specific runtime and a native-code AOT (ahead of time) compiler written in Lisp, itself. SBCL then, for example, can dump&restart memory images - something which is very common for Lisp, though not supported by all implementations.
lispm
It seems it's not processed at runtime for standalone executables
https://sbcl.org/manual/index.html#saving-a-core-image
:save-runtime-options
If true, values of runtime options --dynamic-space-size and --control-stack-size that were used to start SBCL are stored in the standalone executable, and restored when the executable is run. This also inhibits normal runtime option processing, causing all command line arguments to be passed to the toplevel. If :accept-runtime-options then --dynamic-space-size and --control-stack-size are still processed by the runtime. Meaningless if :executable is nil.
lispm
https://sbcl.org/manual/index.html#runtime-options
--dynamic-space-size <megabytes>
Size of the dynamic space reserved on startup in megabytes. Default value is platform dependent.
lispm
CL heap exhaustion
CL is a language with different implementations. The language standard actually does not provide anything on heap exhaustion. Implementations of CL have different ways to deal with runtime heap memory management.
Last I looked, with SBCL there is a fixed heap size at runtime. One can make that max heap size large and the SBCL heap will use that memory as needed. Thus unused memory will not be reserved in memory.
LispWorks (a commercial CL) can grow and shrink the heap at runtime, since the heap is made of memory segments. The max memory size it can grow to in the 64bit implementation is around 4TB (modern Linux, macOS, Windows).
deploying (multi-platform) standalone CL
This again depends on your implementation. There are natively compiled Lisps (like SBCL, Clozure CL, Allegro CL, LispWorks, ...), where both the runtime and the image are native. But that combination can run standalone on a certain platform. That's a typical case for deployment. If you then would target multiple platforms, you would need to provide runtime + image for each platform and select at start the right one.
There are other options, too. Like byte-coded implementations. But that might still have some machine dependencies in the image.
Also, wouldn't ABCL create a standalone JAR too?
"standalone" + given a matching Java runtime.
lispm
Claude Fable 5 has an opinion after two days Lisp hacking, also using two different MCP servers for interactive Lisp programming. One had a very extensive suite of tools.
Question: How would you rate Common Lisp as a programming language for use with LLMs? Compared to other programming languages? How much are macros a problem? The lack of large code bases for training LLMs? The s-expression syntax with many parentheses? Aren't LLMs making lots of mistakes, wrongly placing parentheses or making errors of unbalanced parentheses? given so many problems, are there any upsides?
Answer from Fable 5:
An opinionated answer from direct experience — including the last two days, which were one long field test of exactly this question.
The training-corpus problem is real, but it's the wrong-shaped worry. Yes, the CL corpus is orders of magnitude smaller than Python's or JavaScript's. The practical consequence isn't that models can't write CL — it's two specific failure modes: hallucinated library APIs (inventing a Quicklisp function that doesn't exist), and dialect bleed, which I'd rank as the single most common LLM error in Lisp: Scheme's define and named let, Clojure's defn and threading macros, Elisp idioms leaking into what's supposed to be ANSI CL. That's a corpus-mixing problem, not a size problem. Against it stands something underrated: the corpus that exists is coherent and doesn't rot. CL has been stable since 1994 — code from 1990 is still correct today, my CLHS knowledge is reliable in a way my knowledge of any JS framework simply is not. Small but true beats large but churning more often than people expect.
Parentheses are close to a non-issue, and I'd argue they're an advantage. Balanced-delimiter generation is structurally easy for transformers — it's local and low-entropy. I wrote a fair amount of CL these two days, including multi-page hot-patches evaluated into a running server, and had zero paren failures. More importantly, look at the failure mode: an unbalanced form doesn't parse — the reader rejects it instantly and loudly. Compare Python, where a structural mistake (wrong indentation) is syntactically valid and silently changes meaning. Loud failures are cheap for an agent with a REPL; quiet ones are expensive everywhere. And where paren errors do occur — textual edits into the middle of deep forms — the remedy is structural editing, which s-expressions make trivially possible. LMACS, which we exercised yesterday, is exactly that insight productized: buffers hold forms, not text, and the edit operations are sexp_splice, sexp_raise, sexp_transpose. You cannot build that cleanly for C++.
Macros cost less than advertised, for a reason unique to Lisp. The legitimate worry: a macro-heavy codebase is a private language the model never trained on, with non-obvious evaluation rules. But CL is the one language where the model can interrogate the syntax extension instead of guessing: macroexpand is a tool call. When I fixed the html-parser fetch path, I didn't guess what with-transfer-decoding does — I read its definition and expansion out of the image, and discovered the nonlocal-exit contract (the chunked decoder throws out of the body) that no amount of prior would have predicted. Contrast C++ template metaprogramming or Rust proc-macros, which are far more opaque in practice and can't be asked anything at runtime. Well-designed macros also compress — fewer tokens, more declarative intent, less surface for error. The genuinely dangerous cases are the same as in any language: undocumented cleverness.
The upsides are large, and they're not where people look. For "generate a CRUD app from a blank page", Python wins on prior and library gravity; no point pretending otherwise. But agentic work is shifting from generation to maintenance of running systems — and there CL is arguably the best-positioned language in existence, because the live image gives an agent the tightest verify loop available anywhere: Errors are conversations, not autopsies. This session: a division error left the stack alive; I read the backtrace, evaluated inside the error frame, and resumed via a restart — the suspended computation completed. Everywhere else the agent parses a dead stack-trace string and re-runs from scratch.
Redefinition without restart. Three real server bugs fixed in a serving image — keep-alive wait, MCP dispatcher, HTML tokenizer — hot-patched one defun at a time, verified against live traffic, state intact. The edit-compile-restart-rebuild-state cycle that burns agent time in other stacks just isn't there.
The image is the oracle. The antidote to a small training corpus is asking instead of remembering: who-calls, describe, fboundp, evaluating code to learn the return shape rather than hallucinating it. Introspection converts a knowledge problem into a lookup problem. Homoiconicity pays twice — once for structural editing, once because generated code and analyzed code are the same data structure.
So my rating: as a prior-knowledge language, CL is mid-tier with characteristic dialect-confusion risks. As an agent-environment language — where the loop is propose → check → refine against a live system — it's top-tier, and the historical irony is thick: the interactivity that made Lisp machines pleasant for humans in 1985 turns out to be precisely what LLM agents need in 2026. The missing piece was never the language; it was the bridge. That's what makes this MCP server, and your own tooling work, more than conveniences — they're the difference between a model that writes Lisp and a model that inhabits it.
lispm
Common Lisp is a large language and one can write code without CLOS. Since CLOS is both introspective and reflective, the software is more flexible.
An alternative to CLOS (classes and generic functions) is structures and functions with cases for different structure types. That would be much less introspective and less reflective. Structures in Common Lisp are by the standard not required to be introspective and there is no reflective mechanism for structures.
CLOS itself is more flexible, when it has the optional Meta-Object Protocol. Without it, CLOS is itself is less flexible.
But there are many other parts where you move in a different direction. For example one could inline functions. Thus no late binding and no simple runtime redefinition. Maybe inlining is needed because of speed improvements. Maybe not -> premature optimization is the root of all evil.
Writing a macro instead of a function -> no runtime redefinition without recompiling all places where the macro has been used.
But even for CLOS it might mean that the architecture is developed with some introspection and extension protocol. That CLOS enables both somehow does not mean that in a given software introspection is simple or convenient. Imagine that there is a complex object structure -> one could navigate to the object of interest with various "slot-value" calls. But if that data would be important and accessed often, then it might be useful to provide a function which retrieves the necessary information from a complex object structure. Maybe even provide a query language to find certain objects.
lispm
it mentions the LOOP iteration DSL. What should be added?
lispm
iPad Apps are also possible.
lispm
There is also a sketch of a Listener, terminal and app.
lispm
don't know.
it's based on 0.6.4 and there are now quite substantial changes: more CLOS, CLOS-based conditions, full numeric tower, many bug fixes, an evaluator, CLICC can compile itself, it runs on SBCL and LispWorks, it tries to be more compatible with ANSI CL with COMMON-LISP and COMMON-LISP-USER packages... still missing is LOOP, the pretty printer, and many other things.
lispm
The app now has direct access to Apple's on device LLM model and talks to it over the C interface. The executable is still smaller than 1 MB on macOS.
lispm
Branch Cuts app. Using the CL code from Steele in CLtL2, which generates the Postscript text, which is interpreted by a Swift UI. The whole binary macOS application is just 682kb in size. The CLICC compiler generated the necessary C code from Common Lisp.
Means: one can write Lisp applications with Swift UIs and create really tiny native applications.




https://preview.redd.it/ntdgh4g3j8yh1.png?width=3070&format=png&auto=webp&s=62d86c29f13245bb728d1bab2759d1855f11efcf
I just rebuild the CCL 1.14 IDE from the sources...