Hacker News new | ask | show | jobs
by jfecher 384 days ago
> As I understand it, AE on low level is implemented as a longjmp instruction with register handling (so you can resume).

Not quite. setjmp/lonjmp as they exist in C at least can jump up the call stack but not back down. I mention this at the end of the article but each language implements algebraic effects differently, and efficiency has improved in recent years. Languages can also optimize the effect differently based on how the handler is defined:

- Handlers which are tail-resumptive can implement the effect as a normal closure call.

- Handlers which don't call resume can be implemented as an exception or just return an error value at every step until the function exits the handler.

- Handlers which perform work after resume is called (e.g. `| my_effect x -> foo (); resume (); bar ()` can be implemented with e.g. segmented call stacks.

- Handlers where resume is called multiple times need an equivalent of a delimited continuation.

Another way to implement these generally is to transform the effects into monads. For any set of effects you can translate it into a monad transformer where each effect is its own monad, or the free monad can be used as well. The cost in this approach is often from boxing closures passed to the bind function.

Koka has its own approach where it translates effects to capability passing then bubbles them up to the handler (returns an error value until it gets to the handler).

With just a few restrictions you can even specialize effects & handlers out of the program completely. This is what Effekt does.

There really are a lot of options here. I have some links at the end of the article in the foot notes on papers for Koka and Effekt that implement the approaches above if you're interested.