MaybeT的直觉

3
我正在尝试通过在ghci中运行一些示例来理解MaybeT
λ: import Control.Monad.Trans.Maybe
λ: let x = return $ 42 :: MaybeT (Either String) Int
λ: :t x
x :: MaybeT (Either String) Int

然后,我运行了它:

λ: runMaybeT x
Right (Just 42)

请给我一个值y,使得

runMaybeT y === Left (Just "...")
runMaybeT y === Left Nothing
runMaybeT y === Right Nothing
2个回答

3

您永远不会得到Left NothingLeft (Just ..),因为这里的单子是Either String …,所以在左侧您将始终拥有一个String

以下是您可以获得的内容:

> let y = fail "Failed" :: MaybeT (Either String) Int
> runMaybeT y
Right Nothing
> let y = lift (Left "Failed") :: MaybeT (Either String) Int
> runMaybeT y
Left "Failed"

0

这可能有助于深入了解MaybeT底层的情况...

在IO单子中,我们有计算,例如:

putStrLn "Hello, world!" :: IO ()
getContents :: IO String

等等。所有这些计算都具有类型IO a,实际上,类型变量a是不受限制的-它可以是任何类型。使用return,我们可以为任何类型a创建一个IO计算IO a

您可以将MaybeT IO视为返回Maybe值的那些IO计算。

例如,getContents是一个IO计算,但不是MaybeT IO计算。但是,有一种明显的方法将getContents转换为MaybeT IO计算-只需在其输出中包装Just构造函数即可:

lift getContents   ===   fmap Just getContents

lift 是将一个 IO 计算提升为一个 MaybeT IO 计算的方法。将其应用于 return_IOIO 单子的 return 函数),我们有:

return_(MaybeT IO) === lift return_IO === fmap Just return_IO

也就是说,在 MaybeT IO Monad 中,return 3 相当于在 IO Monad 中使用 return (Just 3)

runMaybeT 和 MaybeT 是互相反转的。

现在看一下 MaybeT 的定义

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

这也描述了在 MaybeT m 中的计算与返回 Maybe 值的 m 中的计算相同的想法。以下函数:

MaybeT    :: m (Maybe a) -> MaybeT m a
runMaybeT :: MaybeT m a  -> m (Maybe a)

它们是彼此的逆元素,实际上除了添加或删除 newtype 包装器之外并不做任何事情。在 IO monad 的情况下:

MaybeT    :: IO (Maybe a) -> MaybeT IO a
runMaybeT :: MaybeT IO a  -> IO (Maybe a)

考虑你问题中的例子,我们可以看到在MaybeT (Either String)中的计算与任何类型aEither String (Maybe a)的值本质上是相同的。这导致了以下可能性:
  • Left某个字符串
  • Right (Just ...)
  • Right Nothing
这些都存在于Either String (Maybe a)中,如果我们将构造函数MaybeT应用于它们中的每一个,我们就得到了对应的值MaybeT (Either String) a
特别地,要找到一个y使得
runMaybeT y == Right Nothing

只需使用:

          y = MaybeT (Right Nothing)

再次强调,runMaybeTMaybeT是彼此的反函数,因此您可以将MaybeT应用于两侧以获得相同的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接