R<E1,R<E2,A>> -- flatten --> R<E1 + E2, A>
R stands for result, E1,E2 are errors.You need to think up a reasonable implementation of +. This is of course easily solvable, you can just add them together. Keep a list of errors in your result instead of one error and you are done. Just keep the +, it is free :p
Validation types work the way you describe and require a monoidal "error" side, but famously do not form monads (though they are applicative functors).
But of left identity, right identity, and associativity, what is violated?
No flattening doesn't make something a monad. Return and flattening are the interesting operations of a monad, that together with the laws makes the monad.
>But of left identity, right identity, and associativity, what is violated?
Well, there is not something violated perse, but you cannot write a flatten operation for something like this:
R<R<u32, E1>, E2>
However you could write it for this: R<R<u32, E1 + E2>, E1 + E2>
(That was what I should have written above btw) Because now the error types are the same.Result<T> instead of Result<T,E> so that it was easier to compose.
This made Kleisli composition easier since I don't have to worry about mismatched types on the Error.
You can see the code at https://github.com/brennancheung/wasmtalk/blob/master/src/fp...
<T, E> can be thought of as a pair, tuple, cartesian product. Likewise you can expand it to as many values as you want.
If type C is just (T, E) then it is really just Result<C> at that point.
The first T can vary but as long as everything after that is fixed to the same type, you can have as many variables/types as you want and it will still be monadic.
Of course for a specific monad to be useful you eventually have to do something specific with it, but again that's completely normal. The point of using the monad abstraction is not to forget that there is a difference between Result and Future, it's to be able to write the common part in a common way - just as, even though you might use a generic List implementation to store lists of integers and lists of strings, you will eventually want to do something with the contents of the list that is specific to either integers or strings.