如何在Haskell中组合monad?

时间:2021-05-28 03:38:14

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...

特别是,我需要能够将CGI monad与IO monad结合起来,但是如何将IO monad与Maybe monad相结合的示例可能会更好......

3 个解决方案

#1


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

我假设你想使用Maybe monad提前终止(比如在C中休息或返回)。

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

在这种情况下,您应该使用MaybeT包中的MaybeT(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.

MaybeT是monad的monad变换器版本。

Monad transformers "add functionality" to other monads.

Monad变形金刚“为其他monad添加功能”。

#2


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:

你没有确切地说你想要如何组合IO和Maybe,但是我假设你有许多函数可以返回你想要轻松组合的IO(也许是a)。基本上你想把IO(也许是a)作为一个独立的类型用它自己的Monad实例来对待:

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:

通过这种方式,您可以使用do-Notation来组合返回IO(可能是a),IO a或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.

通常,组合和修改这样的monad的东西称为monad变换器,GHC附带一个包含monad变换器的包,用于常见情况。如果此monad变换器库中有适合您的场景的内容取决于您希望如何组合Maybe和IO。

#3


In what sense do you want to combine the monads?

在什么意义上你想组合monad?

f :: Int -> IO (Maybe Int)
f x = do
    putStrLn "Hello world!"
    return $ if x == 0 then Nothing else Just x

Can be evaluated to:

可以评估为:

[1 of 1] Compiling Main             ( maybe-io.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 0
Hello world!
Nothing
*Main> f 3
Hello world!
Just 3

#1


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

我假设你想使用Maybe monad提前终止(比如在C中休息或返回)。

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

在这种情况下,您应该使用MaybeT包中的MaybeT(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.

MaybeT是monad的monad变换器版本。

Monad transformers "add functionality" to other monads.

Monad变形金刚“为其他monad添加功能”。

#2


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:

你没有确切地说你想要如何组合IO和Maybe,但是我假设你有许多函数可以返回你想要轻松组合的IO(也许是a)。基本上你想把IO(也许是a)作为一个独立的类型用它自己的Monad实例来对待:

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:

通过这种方式,您可以使用do-Notation来组合返回IO(可能是a),IO a或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.

通常,组合和修改这样的monad的东西称为monad变换器,GHC附带一个包含monad变换器的包,用于常见情况。如果此monad变换器库中有适合您的场景的内容取决于您希望如何组合Maybe和IO。

#3


In what sense do you want to combine the monads?

在什么意义上你想组合monad?

f :: Int -> IO (Maybe Int)
f x = do
    putStrLn "Hello world!"
    return $ if x == 0 then Nothing else Just x

Can be evaluated to:

可以评估为:

[1 of 1] Compiling Main             ( maybe-io.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 0
Hello world!
Nothing
*Main> f 3
Hello world!
Just 3