在IO计算中工作我最终得到case mbValue of …
s的阶梯,并且发现我应该使用Maybe
monad来简化代码。由于它在IO
计算范围内且我需要获得IO
个值,因此我使用了MaybeT
monad变换器,以便lift
IO
计算到{{} 1}}。
现在,我一直在考虑在Maybe
计算中Maybe
之后被values <- mbValue
“剥离”的值,但事实证明这太简单了这里。
如下所示,当使用Maybe
值作为Maybe a
(此处将其传递给a
)时,无法输入check:
read
如果我为import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT)
lol :: IO (Maybe Int)
lol = return (Just 3)
lal :: IO (Maybe String)
lal = return (Just "8")
foo :: IO (Maybe Bool)
foo = do
b <- runMaybeT $ do
x <- lift lol
y <- lift lal
return (x < (read y))
return b ^-- Couldn't match type ‘Maybe String’ with ‘String’
main = foo >>= print
添加了一个输入的洞,我发现它需要一个return (x < (read y))
,这是有道理的,但是当前的绑定还包括
Bool
即,|| y :: Data.Maybe.Maybe GHC.Base.String
|| (bound at /private/tmp/test.hs:14:5)
|| x :: Data.Maybe.Maybe GHC.Types.Int
|| (bound at /private/tmp/test.hs:13:5)
是y
。这当然解释了错误,但我感到困惑。我的理解在哪里错了,我该如何解决这个错误?
答案 0 :(得分:4)
简而言之:用lift
构造函数替换MaybeT
。
请注意
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
和
lift :: (MonadTrans t, Monad m) => m a -> t m a
您在
中使用lift
x <- lift lol
属于
类型lift :: IO (Maybe Int) -> MaybeT IO (Maybe Int)
这就是x
再次成为Maybe Int
的原因。 lift
添加了一个新的MaybeT
图层,该图层与您已有的Maybe
图片无关。
但是
MaybeT :: m (Maybe a) -> MaybeT m a
而不是
x <- MaybeT lol
将用于
类型MaybeT :: IO (Maybe a) -> MaybeT IO a
做正确的事。
答案 1 :(得分:4)
专门针对MaybeT
,lift :: Monad m => m a -> MaybeT m a
。由于lol :: IO (Maybe Int)
,m
为IO
且a
为Maybe Int
,因此为lift lol :: MaybeT IO (Maybe Int)
。
IO (Maybe a)
只是MaybeT IO a
newtype包装中包含的值,因此无需解除它;而是使用MaybeT
构造函数,例如在MaybeT lol
中。
但这不是人们倾向于使用monad变形金刚的方式。相反,只需使用MaybeT
值并根据需要提升:
import Control.Monad
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT, MaybeT)
lol :: MaybeT IO Int
lol = return 3
lal :: MaybeT IO String
lal = return "8"
foo :: IO (Maybe Bool)
foo =
runMaybeT $ do
x <- lol
y <- lal
_ <- lift getLine -- lift (IO String) to MaybeT IO String
_ <- return 100 -- lift any pure value
_ <- mzero -- use the MonadPlus instance to get a lifted Nothing.
return (x < (read y))
main = foo >>= print