我试图通过在MaybeT
中运行一些示例来了解ghci
:
λ: 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
答案 0 :(得分:3)
你永远不会得到Left Nothing
或Left (Just ..)
,因为这里的monad是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"
答案 1 :(得分:0)
这可能有助于深入了解使用MaybeT在幕后发生的事情......
在IO monad中我们有计算,例如
putStrLn "Hello, world!" :: IO ()
getContents :: IO String
等。所有这些计算都具有类型IO a
,实际上类型变量a
是不受限制的 - 它可以是任何类型。使用return
,我们可以为任何类型IO a
创建IO计算a
。
您可以将MaybeT IO
视为返回Maybe值的IO计算。
例如,getContents
是IO
计算,但不是MaybeT IO
计算。但是,有一种明显的方法可以将getContents
转换为MaybeT IO
计算 - 只需将其输出包装在Just
构造函数中:
lift getContents === fmap Just getContents
lift
是将IO
计算推广到MaybeT IO
计算的方法。将此应用于return_IO
(return
monad的IO
函数),我们有:
return_(MaybeT IO) === lift return_IO === fmap Just return_IO
也就是说,return 3
(在MaybeT IO
monad中)与return (Just 3)
monad中的IO
相同。
runMaybeT和MaybeT是彼此的反转
现在看一下definition of 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)
中的计算与任何类型Either String (Maybe a)
的{{1}}类型的值基本相同。这导致了以下可能性:
a
Left
Right (Just ...)
这些都存在于Right Nothing
中,如果我们将构造函数Either String (Maybe a)
应用于每个MaybeT
,我们会在MaybeT (Either String) a
中获得相应的值。
特别要找到y
s.t。
runMaybeT y == Right Nothing
只需使用:
y = MaybeT (Right Nothing)
同样,runMaybeT
和MaybeT
相互反转,因此您可以将MaybeT
应用于双方,从而获得相同的结果。