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 structured token stream to produce new Rust code.
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. The fact that they are not used as much is more of a security issue, not a capability issue, and I am not sure how having eval can be argued as Lisp being the language of agents.
show comments
kazinator
> Symbolic AI lost.
Symbolic AI lost? At what, surely not chess?
A symbolic AI solution to a problem requires vastly less energy. And is deterministic; you can cover it with expected input/output pair regression test cases.
show comments
drob518
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 dangerous. Definitely only for a sandbox. But I wonder how far that can go…
show comments
tosh
9 lines of python:
import json,sys,uuid;from subprocess import getoutput as sh;from urllib.request import Request as R,urlopen
b={"model":"gpt-5.6","prompt_cache_key":uuid.uuid4().hex,"input":[],"tools":[{"type":"custom","name":"shell"}]}
while prompt:=input("> "):
b["input"]+=[{"role":"user","content":prompt}]
while True:
o=(r:=json.load(urlopen(R(sys.argv[1],json.dumps(b).encode(),{"Content-Type":"application/json"}))))["output"]
b["input"]+=o;calls=[i for i in o if i["type"]=="custom_tool_call"];used=r["usage"]["total_tokens"]/10500
if not calls: print(o[-1]["content"][0]["text"],f'\n[{used:06.3f}%]'); break
b["input"]+=[{"type":"custom_tool_call_output","call_id":i["call_id"],"output":sh(i["input"])} for i in calls]
show comments
rcarmo
This is a thing of beauty, no matter what the general feeling in the comments seems to be against LISP. And yeah, you can do it in JS/TS/Python/etc., but somehow it doesn’t feel as elegant.
hankbond
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.
show comments
whartung
I never realized that when chatting with the bot, the entirety of the session was sent each time. I guess I just figured there was some state maintained Out There, rather than simply resubmitted each time.
skapadia
This is beautiful, I can't deny that. But the claim that Claude Code is a fixed set of tools is quite wrong. Claude Code regularly generates new code to carry out tasks, and you can choose to promote those tasks to skills, workflows, etc.
scarredwaits
Nice, but this is the equivalent of always running with `--dangerously-skip-permissions` with all the security implications of that.
show comments
sroerick
I made an interpreted lisp and stored the AST in postgres and exposed the functions with htmx, and honestly it works pretty great.
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 structured token stream to produce new Rust code.
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. The fact that they are not used as much is more of a security issue, not a capability issue, and I am not sure how having eval can be argued as Lisp being the language of agents.
> Symbolic AI lost.
Symbolic AI lost? At what, surely not chess?
A symbolic AI solution to a problem requires vastly less energy. And is deterministic; you can cover it with expected input/output pair regression test cases.
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 dangerous. Definitely only for a sandbox. But I wonder how far that can go…
9 lines of python:
This is a thing of beauty, no matter what the general feeling in the comments seems to be against LISP. And yeah, you can do it in JS/TS/Python/etc., but somehow it doesn’t feel as elegant.
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.
I never realized that when chatting with the bot, the entirety of the session was sent each time. I guess I just figured there was some state maintained Out There, rather than simply resubmitted each time.
This is beautiful, I can't deny that. But the claim that Claude Code is a fixed set of tools is quite wrong. Claude Code regularly generates new code to carry out tasks, and you can choose to promote those tasks to skills, workflows, etc.
Nice, but this is the equivalent of always running with `--dangerously-skip-permissions` with all the security implications of that.
I made an interpreted lisp and stored the AST in postgres and exposed the functions with htmx, and honestly it works pretty great.
Prolog would have been a better choice
it is also possible to sandbox elisp at least. I allow pure functions through by default: https://github.com/elij/macher-agent/blob/main/macher-agent-... -- more an interpreter then straight eval but works as author states
Littered with AI writing tells.