ErikR
ErikR

Reputation: 52039

a generic monadic `(<|>)`?

I'm looking for a more concise / idiomatic way of writing getAorB:

getAorB = do
  a <- getA
  case a of
    Just _  -> return a
    Nothing -> getB

Does this already exist as a library function somewhere?

Note that liftM2 (<|>) getA getB is the same as:

do a <- getA
   b <- getB
   return $ a <|> b

which is different from getAorB since bind is always called on getB even if getA returns a Just.

Upvotes: 2

Views: 119

Answers (4)

Bergi
Bergi

Reputation: 664548

You can use the maybe function (b -> (a -> b) -> Maybe a -> b) with its default value:

getAorB :: Monad m => m a
getAorB = getA >>= maybe getB return

I don't think there's a single function that does this anywhere.

Trying to use an Alternative (such as MaybeT) doesn't work well here imo as it considers the second action to be fallible as well, which your getB isn't. If it if was, you should consider using MaybeT though:

getAorB :: Monad m => m (Maybe a)
getAorB = runMaybeT $ MaybeT getA <|> MaybeT getB

Upvotes: 2

Daniel Wagner
Daniel Wagner

Reputation: 152837

To hide all the transformers:

import Control.Monad.Trans.Maybe

getAOrB :: m (Maybe a) -> m (Maybe a) -> m (Maybe a)
getAOrB getA getB = runMaybeT (MaybeT getA <|> MaybeT getB)

But I would probably just use MaybeT everywhere instead:

getAOrB' :: MaybeT m a -> MaybeT m a -> MaybeT m a
getAOrB' = (<|>)

Note that this type is slightly different than the type of your first implementation; it has the same type as your second implementation but better behavior.

Upvotes: 0

MigMit
MigMit

Reputation: 1697

Sounds like an mplus for MaybeT.

Upvotes: 1

monocell
monocell

Reputation: 1441

Since (<|>) gets it's powers from applicative isn't this impossible? It feels like the type you are looking for is something like

Monad m => a ->[m (Maybe a)] -> m a

instead? Or maybe

Monad m => a -> (a -> Bool) -> [m a] -> m a

Hoogle doesn't give me anything for either.

Upvotes: 0

Related Questions