Equating "algebraic effects" with "continuations" is like saying "if" is just "goto" (which isn't even true, e.g., an if can turn into a cmov or whatever).

The only mystique around algebraic effects is the same mystique there is around monads. I don't know if people have started equating algebraic effects to burritos yet but that's a pretty good way to take something simple and turn it into something confusing.

> Equating "algebraic effects" with "continuations" is like saying "if" is just "goto"

Fair enough. But are you responding to something I said? I didn't make that equation.

> The only mystique around algebraic effects is the same mystique there is around monads. I don't know if people have started equating algebraic effects to burritos yet but that's a pretty good way to take something simple and turn it into something confusing.

Ah, are you saying that fundamentally there isn't really much to algebraic effects and they're much simpler than they're made out to be? If so then it perhaps we agree?

We disagree that they're just continuations (only one of many possible implementation strategies) but agree they're nothing special ;)

I don't think I said they're just continuations. In fact I'm trying to make the point that they're mostly just function calls (and I think in my career I've come across one case where I wanted something beyond function calls (for a constraint solver)). There are "multi-shot" continuations (whether you consider that interface or implementation I don't really mind), which have behaviour than function calls can't express, but I don't know of any algebraic effects beyond that.

What do you think algebraic effects are, if they're not continuations?

EDIT: Ah, based on your comment at https://news.ycombinator.com/item?id=48334737 you might say they're a feature of an intermediate language? So you might take a surface language and "compile to an intermediate language of lambda calculus + algebraic effects", without specifying how that intermediate language is implemented (because it may not even be implemented, per se).

They're really just a protocol. You can implement them in various ways. They will always be some sort of delimited continuations but a "function call" or continuation passing style or anything of the sort does not have to be involved at all.

For example, let us say I don't allow "multi-shot" continuations like in your library, and I'm implementing Algebraic Effects in my own interpreted language.

One way I can implement effects and handlers is to have a handlers get registered in a stack, then when an effect is triggered, save the IP and current stackframe, search for the right handler and jump to it. "resume" then just resets the stackframe, pushes a value into the stack, and sets the saved IP.

(Only saw your edit after posting, sorry, but yes)

> They're really just a protocol.

Thanks, that clarifies where you're coming from. Is it possible to specify this protocol somehow, by defining an interface for it? Or by extending lambda calculus with the bits it needs?

(Maybe that's what the Koka folks do in their papers, and if so feel free to say, "yeah read their papers").

I'm thinking a less formally than that. Protocol in a very layman-y "perform is supposed to do this, resume is supposed to do this".

For example, Koka compiles handlers differently depending if they do multi-shot continuations or not. It can do this because all that matters is "perform is supposed to do this, resume is supposed to do this", not what they turn into (same as "if" turning into "cmov" in certain cases). I think it uses a continuation-passing style sort of implementation, but I can't quite remember.

Daan's libhandler implements effects for C in an entirely different manner. It captures the stack much like my example or a stackful coroutine library would.

I'm sure there a formal definitions in both the koka papers and the libhandler paper, but I just skim that stuff ;)

> Protocol in a very layman-y "perform is supposed to do this, resume is supposed to do this".

OK, but at the very least it has two primitives "perform" and "resume"? And they're supposed to interact in some particular way?

Yeah, there's three things you're supposed to implement: try/handle, perform, and resume. The names can vary (e.g., perform is often called "raise" or "do"). They have well defined interactions.

I don't actually know what the original paper describing what algebraic effects are supposed to do is, I just know them informally from Koka, Effekt, etc.

Interesting, then I wonder if anyone has distinguished them from continuation "protocols" such as shift/reset and prompt/control. Thanks!

Bringing it back to my original point, I guess I'd say that if you already have function calls, exceptions and threading built in to the language then you don't need perform/resume except in niche cases (multi-shot continuations being the only case I know of, but I don't even know of many applications of those).