beginners

Joseph Ferano 2025-08-18T13:47:16.955529Z

I'm doing AoC2024 and I'd like to have Common Lisp style restarts where I can provide values to unbound symbols. I'm guessing farolero is the way to go. I'm trying to get it to work but my clojure is too weak where reading the docs isn't helping me a whole bunch as there are still concepts I still don't understand. Could someone help me?

Joseph Ferano 2025-08-23T04:06:59.259199Z

Thank you for the input @suskeyhose and @p-himik. Sorry I missed these messages. That's good to know. I didn't know about FlowStorm so I'll check it out.

p-himik 2025-08-21T16:20:09.621719Z

Maybe @suskeyhose can help.

2025-08-21T16:21:00.078269Z

oh hello! cool that people are finding farolero

2025-08-21T16:21:51.551179Z

Ok, if I understand this correctly, what you're looking to do is to make it so that you can write code that refers to things that do not exist yet, have the debugger get started when the code attempts to evaluate such an unbound symbol, and allow you to define them from within the debug repl, and then resume execution?

2025-08-21T16:22:07.373429Z

This is my guess because this is something that you absolutely can do in Common Lisp.

2025-08-21T16:26:26.400639Z

Doing this from Clojure is... well let's say it's challenging. The only way that I can think about how it would go is to have some middleware on eval in nrepl that inspects the thing being evaluated, expands macros, and whenever it finds a symbol which is unbound it will instead emit a declare expression to make sure it exists, and then a restart similar to what Joseph described.

2025-08-21T16:26:46.817739Z

The reason that it's this complicated is because there's a fundamental difference in the Common Lisp and Clojure compilation models.

2025-08-21T16:27:58.006779Z

In Common Lisp, symbols themselves have values stored in them, and simply by the reader consuming the source code it produces every symbol which appears in it. That means that by the time you get to evaluating the code, there are no symbols that have no meaning, there are only some symbols which have not had a value set on them.

2025-08-21T16:28:36.556569Z

So when some code is executed in Common Lisp, if a symbol has no value and it is evaluated, then it will signal an error and you can from the debugger give it a value and move on.

2025-08-21T16:28:59.518509Z

But in Clojure, the symbols themselves as produced by the reader aren't what the values are stored on.

2025-08-21T16:29:21.499289Z

Instead, values are stored on Vars, which are created when you evaluate a declare or def form (and a couple other ways).

2025-08-21T16:30:15.358049Z

If you try to compile code that has a symbol which has not been associated with a var in the current namespace, then the compiler will not emit code that will signal an error when it is executed, instead the compiler will throw an exception immediately.

p-himik 2025-08-21T16:32:25.055149Z

It sounds that maybe the most proper way to handle it would be something like the FlowStorm debugger that simply provides its own Clojure version, which in this case would have a custom reader that also defines vars and a custom compiler with some affordances to pause and continue when an unbound var is encountered (which is not needed if another debugger is used on top). Heh, maybe it's even a possible extension for FlowStorm.

2025-08-21T16:35:23.409779Z

Yeah, that would be an option for sure. Unfortunately I don't personally have the capacity to maintain such a fork myself 😅

2025-08-21T16:35:34.547919Z

too many other things to handle already

Joseph Ferano 2025-08-18T13:48:48.590519Z

It seems like it would be some combination of the following;

(restart-case (far/invoke-restart-interactively ::some-restart)
  (::some-restart [a]
    :interactive #(list (far/request-value ::interactive-some-restart))
    a))
That with this?
(defonce on-start
  (alter-var-root far/*debugger-hook* (constantly nil)))