
On Sat, Dec 05, 2009 at 02:13:10PM -0800, Gregory Crosswhite wrote:
The problem comes from the fact that >>= takes a *function* as its second argument, and so if the first argument is an error then we can't evaluate the second argument in order to see if it has an error as well.
Hmm, that's true. I guess I misspoke about liftM2 (+) being able to collect both error messages.
instance Functor E where fmap _ (E (Left error)) = E (Left error) fmap f (E (Right argument)) = E (Right (f argument))
instance Applicative E where pure = E . Right (<*>) (E (Left error2)) (E (Left error1)) = E (Left (error1 ++ error2)) (<*>) (E (Left error)) _ = E (Left error) (<*>) _ (E (Left error)) = E (Left error) (<*>) (E (Right function)) (E (Right argument)) = E (Right (function argument))
OK, this looks like a perfectly valid Applicative instance for E (it satisfies the Applicative laws). So what we have here, it seems, is a type with at least two reasonable Applicative instances, one of which does *not* correspond to a Monad instance. My argument is that it is very strange (I might even go so far as to call it a bug) to have a type with an Applicative instance and a Monad instance which do not correspond, in the sense that pure = return (<*>) = ap although I certainly understand the motivation in this case. Hmm, I'll have to think about this a bit more. The Monad instance which tries passing undefined to the right-hand side of >>= if the left-hand side is an error is strangely compelling, if semantically unsound... -Brent