I've been wanting to experiment with this. There are some libraries in Clojure that try, but it seems that the real value is the interactivity of it while developing? I haven't found the exception handlers to really add much value over normal exception handling at least in Clojure.
As an interesting example, conditions and restarts can be used to implement an interactive system that is composable with other programs. For instance, you can implement a simple y/n question handler as follows:
[yes-or-no-p](http://clhs.lisp.se/Body/f_y_or_n.htm) is an interactive function that reads from the stdin. However, you cannot programatically answer "yes" to fn1, as other functions in the call stack (fn2) has no way to know that fn1 halts because it waits for the input from the stdin. Instead, a condition system allows this:
When you call fn2-automated, an error is signaled, handled by the handler, which invokes a restart 'yes, then :yes is printed. Interactivity is still maintained by fn2-interactive.
It enters the debugger due to the error. In the debugger menu you see additional entries YES and NO.
yes or no?
[Condition of type SIMPLE-ERROR]
Restarts:
0: [YES] YES
1: [NO] NO
2: [RETRY] Retry SLIME REPL evaluation request.
3: [*ABORT] Return to SLIME's top level.
4: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1003167FA3}>)
See? All debugger menus are actually implemented as the restarts, set up at various call stacks. In this implementation of the debugger the way to select YES is to enter 0 or click it on the emacs buffer. In another debugger, it could be entering ":r 0" to the stdin. You can also implement your debugger function, which `read-line` the input stream and only recognizes a specific string, y or n, and set your function to `debugger-hook` to use it (I forgot to mention this in the above example).
Ok right. That's why I feel in Clojure it doesn't provide as much, because it doesn't hook into a debugger.
Having said that, practically, you wouldn't release a tool which has users interact at the debugger, at least for any level of more serious commercial work no?
CL's debugger is just a function, and the key is not to be distracted by the name "debugger".
As said, you can have a custom "debugger" which does not look like a debugger, but a general purpose user interface in the text terminal. For example, being "custom", it can also hide the restarts which are only meaningful for true debugging (like restart 2,3,4). (see detail [1])
It is possible for a debugger to even invoke a GUI (imagine a debugger hook which pops up a window with an OK button) or a web UI (sends a Websocket message to the client, wait for the user to click something on the browser, receive a reply and invoke the restart). In fact, SLIME is written this way: it overloads the debugger hook, and it sends and receives messages to the Emacs TCP client (thus you can click on the menu on an Emacs buffer to restart -- this action is notified back to the underlying lisp process via TCP, which then calls invoke-restart).
[1] You can obtain the list of restarts with COMPUTE-RESTARTS and filter unassociated restarts (similar to a method dispatch but is temporary / has dynamic extent -- see http://clhs.lisp.se/Body/09_adbd.htm).