代码之家  ›  专栏  ›  技术社区  ›  Enlico

运行monad变压器堆产生的任何东西都不是==无?

  •  1
  • Enlico  · 技术社区  · 7 月前

    转载:

    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 ,不禁想到这就是我没有得到我认为在原始示例中应该得到的东西的全部原因。

    根据上述推理,我试图强迫 m === [] 在表达式中 runMaybeT $ maybeQuit (Just 'c') 通过申请 head 结果更符合我的期望:

    λ> isNothing (head $ runMaybeT $ maybeQuit (Just 'q'))
    True
    λ> isNothing (head $ runMaybeT $ maybeQuit (Just 'c'))
    False
    

    但我仍然不明白使用有什么问题 runIdentityT .

    1 回复  |  直到 7 月前
        1
  •  4
  •   Joseph Sible-Reinstate Monica    7 月前

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

    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 ,这与 没有什么 .

    你的例子有几个额外的间接层,但最终,同样的事情也在发生。 runIdentityT 这是转移注意力;你的表达式是如此的多态,以至于它在任何地方都不做任何事情。

    如果你不明白为什么你的表情基本上和 return无 ,记住 mzero 您正在使用的定义如下:

    instance (Monad m) => MonadPlus (MaybeT m) where
        mzero = MaybeT (return Nothing)
    

    不是这个:

    instance (MonadPlus m) => MonadPlus (MaybeT m) where
        mzero = MaybeT mzero