Live data from Hacker News

An agent in 100 lines of Lisp

thebeach.dev

41–50 of 84 posts

Re: An agent in 100 lines of Lisp

#41

I like Lisp, I’ve used Common Lisp with a passion, but this doesn’t seem like a valid argument for Lisp. Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify, hence allowing Lisp macros. While some might disagree, I see Rust macros as the closest thing that demonstrates homoiconicity in mainstream Algol-based languages, as Rust macros modify the loosely structure…

> Eval, on the other hand, that’s more of a capability that comes from Lisp’s runtime, which used to be unique when Lisp was thriving, but not anymore — JS, Python, Ruby, all of the runtime-based languages have an eval function.

And it's good we have those for troubleshooting but those eval still offer nowhere near the power of a Lisp REPL.

> and I am not sure how having eval can be argued as Lisp being the language of agents

I've seen several Lisp programmers saying that it's really the REPL (and the 'E' in REPL is for "Eval") that is the godsend when working with LLMs.

With LLMs we've seen terminals/ssh/tmux and CLI tools calling making a huge comeback (not that they ever went very far).

Now I wouldn't be surprised if we were soon to see a Lisp AI harness also using extensively the REPL becoming succesful.

It's too early to tell it's not a powerful combo (LLMs + Lisp REPL).

Re: An agent in 100 lines of Lisp

#42

I like Lisp, I’ve used Common Lisp with a passion, but this doesn’t seem like a valid argument for Lisp. Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify, hence allowing Lisp macros. While some might disagree, I see Rust macros as the closest thing that demonstrates homoiconicity in mainstream Algol-based languages, as Rust macros modify the loosely structure…

> Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify I think a more accurate description is that lisp code is just cons cells and cons cells is both how we write the code and how the runtime itself implements lists. So there’s basically no distinction between a lisp list and the text representation of the source. Rust and its macros is a different situation bec…

> I think a more accurate description is that lisp code is just cons cells and cons cells is both how we write the code and how the runtime itself implements lists. So there’s basically no distinction between a lisp list and the text representation of the source.

Heresy I suppose, but doesn't feel (to me) like it "specifically" has to be cons cells, as long as it's a "list" of some sort, regardless of the specific type of list, while I'd say "cons cells" is a specific implementation of a list, famously implemented by Common Lisp and similar lisps.

Besides that I agree with you, the code you write and the code the compiler uses is the same, that's why it gets easy to edit with code itself. Rust and similar don't have this feature at all, it's very different experience writing macros with lots of special syntax, compared to just writing "normal" code doing the same sort of operations. "Doing a loop of X" isn't the same inside of a normal runtime function body, as when you want to do a loop of arguments for the function signature in a macro, as just one simple example.

Not to mention in Rust you have two different types of macros, declarative vs procedural macros, already speaking to that the entire concept of homoiconicity isn't there. You want it to be easy to implement a read, evaluate, print and loop back workflow by passing native data through the entire chain, except parsing the initial user-input string into your AST (whatever shape that ends up being), which pretty-printed (basically) looks the same as the user-input.

Re: An agent in 100 lines of Lisp

#43

I like Lisp, I’ve used Common Lisp with a passion, but this doesn’t seem like a valid argument for Lisp. Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify, hence allowing Lisp macros. While some might disagree, I see Rust macros as the closest thing that demonstrates homoiconicity in mainstream Algol-based languages, as Rust macros modify the loosely structure…

Does eval in these other languages evaluate ASTs or strings? It makes a difference.

Re: An agent in 100 lines of Lisp

#45

Earlier quoted context omitted.

> Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify I think a more accurate description is that lisp code is just cons cells and cons cells is both how we write the code and how the runtime itself implements lists. So there’s basically no distinction between a lisp list and the text representation of the source. Rust and its macros is a different situation bec…

> I think a more accurate description is that lisp code is just cons cells and cons cells is both how we write the code and how the runtime itself implements lists. So there’s basically no distinction between a lisp list and the text representation of the source. Heresy I suppose, but doesn't feel (to me) like it "specifically" has to be cons cells, as long as it's a "list" of some sort, regardless of the specific ty…

> Heresy I suppose, but doesn't feel (to me) like it "specifically" has to be cons cells, as long as it's a "list" of some sort

Yeah, "cons" is definitely a implementation detail. Maybe the central ideia is just "parenthesized s-expr".

Re: An agent in 100 lines of Lisp

#46
post #40
post #35

So, writing an agent in Lisp is interesting but not particularly novel. If there’s a big idea here it’s giving Lisp’s eval function to the AI as a tool. Yes, AIs write Python and Bash all day long already, but those scripts are run out of process. In this case, the AI can modify the process running the harness, extending it directly and potentially changing it (evolving it). That’s powerful. And obviously quite dange…

There is no good reason for running this in-process. The maximally inefficient Fibonacci function in the article is a good demonstration why: Call it with a slightly larger number, and your agent slows to a crawl, with no way to enforce a timeout. Call it with a slightly larger number yet, and you might bring your agent down entirely, with no way to recover. There is a case to be made for a dynamically evolving "tool…

Lately I've been adding a repl service to my docker compose configs so the agent can easily send fragments of code for execution in the project context without incurring the clojure startup costs each time.

So cool to watch the AI get into a tight learning loop when it has access to all the internal data structures.

Re: An agent in 100 lines of Lisp

#47
post #40
post #35

So, writing an agent in Lisp is interesting but not particularly novel. If there’s a big idea here it’s giving Lisp’s eval function to the AI as a tool. Yes, AIs write Python and Bash all day long already, but those scripts are run out of process. In this case, the AI can modify the process running the harness, extending it directly and potentially changing it (evolving it). That’s powerful. And obviously quite dange…

There is no good reason for running this in-process. The maximally inefficient Fibonacci function in the article is a good demonstration why: Call it with a slightly larger number, and your agent slows to a crawl, with no way to enforce a timeout. Call it with a slightly larger number yet, and you might bring your agent down entirely, with no way to recover. There is a case to be made for a dynamically evolving "tool…

Clearly, you’re not going to do it for just Fibonacci. And yes, you can always rewrite the agent code, quit, and restart to modify the agent. This is just like using an LLM to modify Pi and then restarting, which is done today. But being able to rewrite code in a live, running system is useful for all the reasons that Lispers have done it that way for 50+ years. In some cases, you can’t just serialize your state and reload it easily. Sometimes, for instance, you might not even have access to the whole state because some of it resides on a remote server.

Re: An agent in 100 lines of Lisp

#48

Earlier quoted context omitted.

Right but given that the agent only outputs text, and agents are perfectly happy writing python, the supposed benefit of Lisp is completely irrelevant here.

> the supposed benefit of Lisp is completely irrelevant here Yeah, it's a small example (it's in the title, "100 lines") so obviously doesn't highlight the best benefits once you reach larger codebase size. Still think ~8 lines for the core loop is probably more elegant, readable and concise than you can achieve in other algol/C-like languages, but happy to be shown that I'm wrong :)

Most of the code in agents is to handle unhappy paths and human friendly interfaces. I’m sure you could trim most languages core loop too if you discarded all the stuff that actually make agents peasant to use.

Re: An agent in 100 lines of Lisp

#49
post #47
post #40

Earlier quoted context omitted.

There is no good reason for running this in-process. The maximally inefficient Fibonacci function in the article is a good demonstration why: Call it with a slightly larger number, and your agent slows to a crawl, with no way to enforce a timeout. Call it with a slightly larger number yet, and you might bring your agent down entirely, with no way to recover. There is a case to be made for a dynamically evolving "tool…

Clearly, you’re not going to do it for just Fibonacci. And yes, you can always rewrite the agent code, quit, and restart to modify the agent. This is just like using an LLM to modify Pi and then restarting, which is done today. But being able to rewrite code in a live, running system is useful for all the reasons that Lispers have done it that way for 50+ years. In some cases, you can’t just serialize your state and…

> Sometimes, for instance, you might not even have access to the whole state because some of it resides on a remote server.

Not sure what you mean. The system I outlined is one where some "state" resides outside the process in a separate server. You don't need to serialize that, you just need to serialize the information to need to reconnect.

And my first point is even more relevant the more complex/distributed/brittle you make the whole thing: The more important it is for some specific process to stay alive no matter what, the less you want to live-slop code into it.

(Edit: Yes I'm aware of the live-patched space probe story. Human live-patching is not the same as letting an LLM try to one-shot the correct patch.)

Re: An agent in 100 lines of Lisp

#50
post #16
post #2

Maybe this is a reductive comment, but how does this differ from just letting your agent bash tool a `python -c` command (or anything of that class)? I'm not really getting where this is a "wow" moment? It is always nice to appreciate how much power you get out of (Model + the absolute bare minimum of control flow). There is just so much baked into the models now that given an inch they will take a mile.

If you give your agent a `bash` or `python -c` tool, it starts a separate process that produces some output and then exits. After that, only the output and the exit code are available. In contrast, `eval` runs the code in the same execution context as the agent loop. When `eval` finishes, that execution context still exists. For example, any functions defined during an `eval` call remain available for later use.

That’s a distinction in search of a reason though.

Being able to run code in the same unix process or a new one doesn’t really matter all that much in the context of self modifying code. But even if we cared about that, this isn’t a LISP specific feature. All dynamic languages support eval.

And having the agent cache the tool for reuse is a really trivial problem to solve. Though I do agree that LISP makes this much easier than in many other languages.

This is certainly a cool tech demo. But the claims of its novelty are overstated

Post reply on HN