4 ms·
Though both Result and Future types can be described as a monadic shape, it only works if you fix the Error type. Even then, you've lost the value in the Resul
by couchand 7y ago
Though both Result and Future types can be described as a monadic shape, it only works if you fix the Error type. Even then, you've lost the value in the Result entirely. The interesting and useful thing about a Result is the part of it that breaks from the monadic mold, the error case.
- eximius 7y agoHow does the error case break the monadic model? All of the monad rules still apply, I think.
- pinopinopino 7y agoThe error needs to be a monoid to be able to flatten the Result, if it is not, it will break, you will lose information. E.g. if you have: 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
- lmm 7y agoThis is completely wrong. Result is either success or failure, so an R<E1, R<E2, A>> can never contain both E1 and E2 at the same time. Validation types work the way you describe and require a monoidal "error" side, but famously do not form monads (though they are applicative functors).
- pinopinopino 7y agoA true that, long day and have been working with shapeless in scala, where type level and value level mixes up :)
- eximius 7y agoWhile compelling, flattening doesn't make something a monad, does it? Not snark, if that's a consequence of one of the three laws, I'm just unaware of it. I know what monads are but I'm not practised with them. But of left identity, right identity, and associativity, what is violated?
- pinopinopino 7y agoSo, I was a bit wrong with the monoid, I meant to add them on typelevel by using a sumtype. Sorry, sometimes bit confused after work. 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.
- bcheung 7y agoI created a Result style interface in Typescript and made the decisions to fix the Error to a single type for this very reason. 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/Result.ts https://github.com/brennancheung/wasmtalk/blob/master/src/fp...
- whelming_wave 7y agoI've found this kind of pattern much nicer in an application context. Rust sort of has this going on with anyhow[1] for applications and thiserror[2] for libraries (or just writing your own Error type). [1]: https://crates.io/crates/anyhow https://crates.io/crates/anyhow [2]: https://crates.io/crates/thiserror https://crates.io/crates/thiserror
- klodolph 7y agoResult doesn’t break from the monadic mold.
- efnx 7y agoIt does in that it has two type variables. In Haskell Either is not a monad - (Either a) is.
- bcheung 7y agoThe number of variables doesn't matter, as long as they are the same type is the part that matters. <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.
- efnx 7y agoYou’re reducing two type variables down to one. The number of type variables matter. The kind of the type matters. Look at the definition of Monad for Either. You’ll see.
- lmm 7y agoFor any E, Result<E, ?> forms a valid monad. So yes technically Result is a family of monads rather than a single monad, just as technically the monad is not the type itself but the combination of the type and two functions defined on that type, but that's irrelevant pedantry most of the time.
- lmm 7y agoNonsense. Yes Results can only be composed monadically if they have the same error type, but that's true for any other way of composing Results too - if you want to use Rust's ? operator then you need to make sure all the results you're going to use it on share (or are at least are convertible to) the same error type. 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.