MaybeT 计算中的类型
Types in MaybeT computation
在 IO 计算中,我得到了一个 case mbValue of …
的阶梯,我发现我应该使用 Maybe
monad 来简化代码。因为它在 IO
计算中,我需要获得 IO
值,所以我使用了 MaybeT
monad 转换器,这样我就可以 lift
IO
计算到 Maybe
.
现在,我一直在考虑在 Maybe
计算中的 values <- mbValue
之后将值“剥离”其 Maybe
ness,但事实证明这太简单了这里是启发式。
如下所示,当使用 Maybe a
值作为 a
时(此处将其传递给 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
是 Maybe String
。这当然解释了错误,但我很困惑。我的理解哪里错了,我该如何解决这个错误?
简而言之:用 MaybeT
构造函数替换 lift
。
注意
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
并做正确的事。
专用于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
新类型包装器中的值,因此无需解除它;而是使用 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
在 IO 计算中,我得到了一个 case mbValue of …
的阶梯,我发现我应该使用 Maybe
monad 来简化代码。因为它在 IO
计算中,我需要获得 IO
值,所以我使用了 MaybeT
monad 转换器,这样我就可以 lift
IO
计算到 Maybe
.
现在,我一直在考虑在 Maybe
计算中的 values <- mbValue
之后将值“剥离”其 Maybe
ness,但事实证明这太简单了这里是启发式。
如下所示,当使用 Maybe a
值作为 a
时(此处将其传递给 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
是 Maybe String
。这当然解释了错误,但我很困惑。我的理解哪里错了,我该如何解决这个错误?
简而言之:用 MaybeT
构造函数替换 lift
。
注意
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
并做正确的事。
专用于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
新类型包装器中的值,因此无需解除它;而是使用 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