9

In the error monad, the first failure halts any execution further just carrying the fault through any following binds.

What monad halts on success only carrying forward successes, and basically swallowing any faults and trying the next bind disregarding the failure of the previous one?

The error monad could maybe be used for this treating failure like success, but I'm curious if the default libraries have a monad for this specific purpose, almost like an Or monad in my mind "Do this, or that"

Edit:

Behaviour would be:

Left "fail" >>= (\x -> Right "win") >>= (\x -> Left "ahh neener") >>= (\x -> Right (x + " yay"))

In the error monad the first left value is just carried forward, so the result of that is Left "fail". The behaviour I want is where the above returns Right "win yay" it's a trivial monad to implement I could write myself, but figured something existed to do such (maybe not using Either, but that's the first thing that comes to mind for such behaviour).

Jimmy Hoffa
  • 16,039
  • 3
  • 69
  • 80

1 Answers1

4

What you need is MonadPlus (see also Haskell wiki). It defines

mzero :: m a

which represents an unspecified error, and

mplus :: m a -> m a -> m a

which tries the second computation, if the first one fails. A few auxiliary functions are provided too:

-- Extends `mplus` to lists of computations:
msum :: MonadPlus m => [m a] -> m a
-- Fails a computation conditionally.
guard :: MonadPlus m => Bool -> m ()
-- Filter (fail) computations that don't satisfy the predicate.
mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a

Instances of MonadPlus can be divided into two categories:

  1. mplus combines all possible results from both its arguments (satisfies Left Distribution law). [] and Seq are probably the only instances with this behavior.
  2. mplus selects the left argument, if it contains a valid value, otherwise it selects the right one (satisfies Left Catch law). Instances with this behavior are Maybe, Either, STM and IO.

(MonadPlus instance of Either used to be defined in Control.Monad.Error as

instance (Error e) => MonadPlus (Either e) where
    mzero            = Left noMsg
    Left _ `mplus` n = n
    m      `mplus` _ = m

but for some reason it seems to be missing in the current version.)

See also MonadPlus on Wikibooks and MonadPlus definition for Haskell IO.

Petr
  • 5,507
  • 3
  • 29
  • 46
  • Thanks, sounds like monadplus list is the thought I had. – Jimmy Hoffa Jan 20 '13 at 13:35
  • @JimmyHoffa I forgot to mention that `Seq` is also an instance of `MonadPlus`. I'd strongly recommend it over `[]`, because concatenation (`mplus`) for `Seq` is _O(log n)_ whereas concatenation of lists is _O(n)_. – Petr Jan 20 '13 at 13:46
  • The haskell wiki is very illuminating, sounds like the haskell community is pondering which way it should go in the same way I'm pondering which way I want it to work; whether I want it to be an Or as a "This or that" or a then, "This then that" where the first one failing causes behaviour like Or using the pre-failure value for the next one, but a success still calls the next one unlike Or and uses the value returned from the first function. – Jimmy Hoffa Jan 22 '13 at 17:34
  • Yes, I support the [MonadPlus reform proposal](http://www.haskell.org/haskellwiki/MonadPlus_reform_proposal), I believe this would clarify things a lot. – Petr Jan 22 '13 at 18:07