The problem with monads is their composition. Ie. questions like how is the do notation supposed to work if I want to return:
* an Option<Async> or Async<Option>?
* both an Option and an Async (a product, or tuple type)?
* either an Option or an Async (a sum, or tagged union type)?
Monad transformers can be written for wrapping monads into other monads (as a simple example, an Option is equivalent a List with exactly zero or one elements), but they're something of an ad hoc solution and do not generalize well.
This is fundamentally an issue similar to the "function color" problem, or the fact that exceptions in most languages are a limited, ad hoc effect system and do not compose well. Java gave checked exceptions a bad name largely because of their lack of compositionality, but it's more that the particular implementation is poor.
To be fair, that was in 1994 and nobody had worked out these things yet even in the academia. Algebraic effects are the attempt to do just that.
Right, I understand the history (although I'm not sure I'd say that exception don't compose well) and I understand that "algebraic effects" are an attempt at something better. But I don't understand whether they're something that can be precisely defined or just informal terminology for "a better sort thing for dealing with effects".
You can precisely define any particular model, but not all work in the area shares the same model. I think you know about the capability-passing model, which is quite different to the algebraic effects (e.g. row types) models.
The general ideas are:
* effects are handled by handlers (called capabilities in the capability-passing model)
* function signatures describe the effects that are used
* effectful code is written in direct style, not monadic style
OK, and in the general case a handler allows its body to "perform" an action, and when the action is performed it has the ability to "respond" to it in (in some cases) a very flexible way, running it never, or multiple times, or in a modified environment, or possibly even passing it out of the scope of the handler entirely.
> function signatures describe the effects that are used
Would you say this is not possible in an untyped language then?
> effectful code is written in direct style, not monadic style
> OK, and in the general case a handler allows its body to "perform" an action...
Yes, although not all systems allow this, as implementing full continuations is involved and can hurt performance.
> Would you say this is not possible in an untyped language then?
You can definitely implement the ideas of algebraic effects in an untyped language, but you lose one of the benefits.
> I don't understand the distinction here
Monadic code is code where the order of evaluation is specified by bind / flatMap. Direct-style just uses the language's built-in control flow. See https://noelwelsh.com/posts/direct-style/ for more
* an Option<Async> or Async<Option>?
* both an Option and an Async (a product, or tuple type)?
* either an Option or an Async (a sum, or tagged union type)?
Monad transformers can be written for wrapping monads into other monads (as a simple example, an Option is equivalent a List with exactly zero or one elements), but they're something of an ad hoc solution and do not generalize well.
This is fundamentally an issue similar to the "function color" problem, or the fact that exceptions in most languages are a limited, ad hoc effect system and do not compose well. Java gave checked exceptions a bad name largely because of their lack of compositionality, but it's more that the particular implementation is poor.
To be fair, that was in 1994 and nobody had worked out these things yet even in the academia. Algebraic effects are the attempt to do just that.