运行 monad 转换器堆栈不会生成任何内容 == 什么都没有?

问题描述 投票:0回答:1

重现:

cabal repl --build-depends=mtl-prelude,transformers
λ> import Data.Mayb
λ> import Control.Monad
λ> import Control.Monad.Trans.Identity
λ> import MTLPrelude
λ> :{
ghci| maybeQuit :: MonadPlus m => Maybe Char -> MaybeT m (Maybe Char)
ghci| maybeQuit key = do
ghci|   case key of
ghci|     Just 'q' -> mzero
ghci|     Just '\ESC' -> mzero
ghci|     _ -> return key
ghci| :}
λ> runIdentityT $ runMaybeT $ maybeQuit (Just 'c')
Just (Just 'c')
λ> runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
Nothing

到目前为止一切顺利。

但是然后:

λ> (runIdentityT $ runMaybeT $ maybeQuit (Just 'q')) == Nothing 
False
λ> isNothing (runIdentityT $ runMaybeT $ maybeQuit (Just 'q'))
False

什么?!


我确实看到表达式有点多态,

λ> :t runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
  :: MonadPlus f => f (Maybe (Maybe Char))

但我完全不确定这如何意味着打印为

Nothing
的东西可能不是
(==) Nothing


对于上下文,我在单子堆栈中运行

maybeQuit
(其中有
MaybeT
和其他变压器),底部有
IO
,它按预期工作,但它是实现,因此是类型,不需要
IO
的力量,所以我试图在一个 monad 中测试它,而不是
IO
,这就是我提出这个问题的方式。

事后看来,我确实开始看到一些我不太明白的东西:我看到

:t runMaybeT $ maybeQuit (Just 'q')
MonadPlus m => m (Maybe (Maybe Char))
,这是我所期望的,但是然后应用
runIdentityT
给出类型
MonadPlus f => f (Maybe (Maybe Char)
,这是相同的事情,所以我一定误解了
IdentityT
的含义/目的,并且忍不住认为这就是整个原因是我没有得到我认为我应该在原始示例中得到的东西。

haskell option-type monad-transformers
1个回答
0
投票

要了解发生了什么,请考虑这个更简单的示例:

ghci> import Data.Maybe
ghci> weird = return Nothing
ghci> weird
Nothing
ghci> weird == Nothing
False
ghci> isNothing weird
False
ghci> :t weird
weird :: Monad m => m (Maybe a)
ghci> 

当您刚输入

weird
时,GHCi 默认
m
IO
(因此整体类型为
IO (Maybe a)
),然后为您评估 IO 操作,结果为
Nothing
。当输入
weird == Nothing
isNothing weird
时,
m
被强制为
Maybe
(所以整体类型为
Maybe (Maybe a)
),所以
return Nothing
变成了
Just Nothing
,这与
Nothing
不同。

您的示例有几个额外的间接层,但最终,同样的事情正在发生。

© www.soinside.com 2019 - 2024. All rights reserved.