Hacker News new | ask | show | jobs
by spankalee 149 days ago
That Midori article looks great, I'll give that a closer read. I actually used to work with Bob, and am familiar with the (wonderful!) function color article.

I think my biggest question might be addressed in the Midori article: with things like bounds checks and checked casts you already have exceptions (or panics), so should you have a way to capture them anywhere on the stack? Are they recoverable in some programs? So should you have try/catch even if you try to make most errors return values?

Another set of questions I have is around reified stacks. Once you have features like generators and async functions, and can switch stacks around, you're most of the way to resumable exceptions. I don't yet fully grok how code as the resume site is supposed to deal with a resume, but maybe resumable exceptions are a reason to keep them.

2 comments

I'd never heard of "resumable exceptions" before, so I searched them up [1][2]. Is this another name for the language feature called "effect handlers" in OCaml 5?

[1] https://osa1.net/posts/2024-11-04-resumable-exceptions.html

[2] https://softwareengineering.stackexchange.com/questions/8033...

Yes, afaiu at least, effects and resumable exceptions are nearly the same, and you can implement one with the other.
Pretty much every language has a form of resumable exception known as a "function call". It's hard for me to understand why no one in the algebraic effects/effect handlers community has noticed this yet.
This is the difference between functions and effect handlers, to my understanding:

Functions map inputs to outputs, with a type signature that looks like A -> B. Functions may be composed, so if you have f: A -> B and g: B -> C, you have gf: A -> C. Function composition corresponds with how "ordinary" programming is done by nesting expressions, like g(f(x)).

Sometimes, the function returns something like Option<B> or Future<B>. "Ordinary" function composition would expect the subsequent function's input type to be Future<B>, but frequently you need that input to have type B. Therefore, optionals or futures require "Kleisli composition," where given f: A -> Future<B> and g: B -> Future<C>, you have gf: A -> Future<C>. Kleisli composition corresponds with "monadic" programming, with "callback hell" or some syntactic sugar for it, like:

    let y = await f(x);
    g(y)
Effect handlers allow you to express the latter, "monadic" code, in the former, "direct style" of ordinary function calls.