Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I combine monads in Haskell?

Particularly, I need to be able to combine the CGI monad with the IO monad, but an example of how to combine the IO monad with the Maybe monad might be even better...

like image 629
Chris W. Avatar asked Jul 14 '09 16:07

Chris W.


People also ask

How do monads work Haskell?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What does >> mean in Haskell?

Essentially, a >> b can be read like "do a then do b , and return the result of b ". It's similar to the more common bind operator >>= .

What is bind Haskell?

Bind takes a non-composable function f and returns a new function g that accepts the monadic type as input and returns the monadic type. g is composable. The unit function takes an argument of the type that f expected, and wraps it in the monadic type.

Is either a monad Haskell?

Strictly speaking, Either cannot be a monad, as it has kind Type -> Type -> Type ; Either String can be (and is), because it has kind Type -> Type .


2 Answers

I assume you want to use the Maybe monad for early termination (like break or return in C).

In that case you should use MaybeT from the MaybeT package (cabal install MaybeT).

main = do
  runMaybeT . forever $ do
    liftIO $ putStrLn "I won't stop until you type pretty please"
    line <- liftIO getLine
    when ("pretty please" == line) mzero
  return ()

MaybeT is a monad transformer version of the maybe monad.

Monad transformers "add functionality" to other monads.

like image 113
yairchu Avatar answered Oct 07 '22 23:10

yairchu


You don't exactly say how you want to combine IO and Maybe, but I assume you have many functions that return IO (Maybe a) that you want to combine easily. Basically you want to treat IO (Maybe a) as a separate type with it's own Monad instance:

newtype IOMaybe a = IOM (IO (Maybe a))

-- "unpack" a value of the new type
runIOMaybe :: IOMaybe a -> IO (Maybe a)
runIOMaybe (IOM a) = a

instance Monad IOMaybe where
   -- bind operator
   (IOM ioa) >>= f = IOM $ do
      a <- ioa
      case a of
         Nothing -> return Nothing
         Just v  -> runIOMaybe (f v)

   -- return
   return a = IOM (return (Just a))

-- maybe also some convenience functions
returnIO :: IO a -> IOMaybe a
returnIO ioa = IOM $ do
   v <- ioa
   return (Just v)

returnMaybe :: Maybe a -> IOMaybe a
returnMaybe ma = IOM (return ma)

With this you can use the do-Notation to combine functions that return IO (Maybe a), IO a or Maybe a:

f1 :: Int -> IO (Maybe Int)
f1 0 = return Nothing
f1 a = return (Just a)

main = runIOMaybe $ do
   returnIO $ putStrLn "Hello"
   a <- returnMaybe $ Just 2
   IOM $ f1 a
   return ()

Generally something that combines and modifies monads like this is called a monad transformer, and GHC comes with a package that includes monad transformers for common cases. If there is something in this monad transformer library that fits your scenario depends on how exactly you want to combine Maybe and IO.

like image 44
sth Avatar answered Oct 07 '22 23:10

sth