【问题标题】:How do I combine monads in Haskell?如何在 Haskell 中组合单子?
【发布时间】:2010-11-10 17:32:08
【问题描述】:

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

【问题讨论】:

标签: haskell functional-programming monads monad-transformers


【解决方案1】:

我假设您想使用 Maybe monad 提前终止(例如 C 中的 break 或 return)。

在这种情况下,您应该使用 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 是 Maybe monad 的 monad 转换器版本。

Monad 转换器“添加功能”到其他 monad。

【讨论】:

  • mtl 中还有 ErrorT 也毫无价值,而且它也实现了 MonadPlus,这意味着上面的代码在 Error monad 中几乎不会改变。 (变化在于 ErrorT 的“Left”部分需要类型签名,因为“mzero”不够具体。)
  • @jrockway: 左边的类型需要Error 实例,这有点不方便,因为MaybeT 实际上与ErrorT () 类似,但这是不允许的,因为有不是instance Error ()。最好使用EitherT,但这也需要额外的包。
【解决方案2】:

您没有确切说明您想如何组合IO 和Maybe,但我假设您有许多返回IO (Maybe a) 的函数,您想轻松组合它们。基本上,您希望将 IO (Maybe 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)

有了这个,您可以使用do-Notation 来组合返回IO (Maybe 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 ()

通常像这样组合和修改 monad 的东西称为 monad transformer,而 GHC 附带一个 package,其中包括用于常见情况的 monad 转换器。这个 monad 转换器库中是否有适合您的场景的东西取决于您希望将 Maybe 和 IO 结合起来的方式。

【讨论】:

  • 如果你不知道,你可以通过声明newtype IOMaybe a = IOM { runIOMaybe :: IO (Maybe a) }来自动创建runIOMaybe
【解决方案3】:

你想在什么意义上结合单子?

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

可以评估为:

[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

【讨论】:

  • 你没有在 Maybe 上进行计算,因此 Maybe 是一个 monad 的事实是无关紧要的。
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多