我有一个一元计算。在某些时候,由于 monadic 模式匹配,它开始需要 MonadFail 约束。
我的简单解决方法是用这个运行它:
fmap (either error id) . runErrorT
Run Code Online (Sandbox Code Playgroud)
然而哎哟:
Deprecated: "Use Control.Monad.Trans.Except instead"
Run Code Online (Sandbox Code Playgroud)
所以它似乎已ErrorT
被弃用,我要使用它ExceptT
。从外面看这听起来不错,但似乎 ExceptT 根本不是替代品! 看看实例声明:
instance (Monad m, Error e) => MonadFail (ErrorT e m)
instance MonadFail m => MonadFail (ExceptT e m)
Run Code Online (Sandbox Code Playgroud)
ErrorT
提供MonadFail 实现。 ExceptT
只是举起它。
我不太确定从哪里开始。
我的代码最终不会有可反驳的绑定。这是静态已知可以工作但尚未向类型检查器证明的情况之一。我会到达那里,但需要一些时间。(比如,我将需要依赖类型,所以我需要学习依赖类型。这需要一段时间。)
但与此同时,我的代码需要绑定,error
如果我搞砸了,我真的可以被调用。
看起来我正在寻找的是一些通用MonadFail
实现,它允许我......好吧,用不匹配的模式做我想做的事。 ErrorT
做了这个,ExceptT
没有。
我的非弃用选项是什么?
这个问题问得好!我什至编写了一个实际的库FailT
来解决这个优雅失败的问题MonadFail
。
我不确定确切的设置是什么,但我想用一个具体的例子来回答这个问题。假设我们有一个单子动作接受另一个产生的单子动作MyType
,我们可以打赌我们的家庭农场会是这种Expected
情况:
data MyType a = Expected a | Unexpected a\n deriving (Show)\n\nmyFunc :: (Show a, MonadFail m) => m (MyType a) -> m String\nmyFunc t = do\n Expected a <- t\n pure $ show a\n
Run Code Online (Sandbox Code Playgroud)\nbase
不幸的是,在或其他与 GHC 连接的库中没有合适的解决方案,例如transformers
或mtl
。
就像你已经知道的那样ErrorT
这本来可以完美地实现这一点,但出于充分的理由,它已被弃用。
ExceptT
本来可以提供一个合理的MonadFail
实例,但这对于向后兼容性来说是相当有问题的。
正如评论中所建议的那样,ExceptT
用 a包裹起来newtype
并提供自定义MonadFail
实例肯定会起作用,但是谁希望每次遇到此问题时都将其包含在代码库中。为了完整起见,这里是一个最小的独立解决方案:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}\n\nimport Control.Monad.Trans.Except\n\nnewtype ResultT m a = ResultT (ExceptT String m a)\n deriving (Functor, Applicative, Monad)\n\ninstance Monad m => MonadFail (ResultT m) where\n fail = ResultT . throwE\n\nrunResultT :: ResultT m a -> m (Either String a)\nrunResultT (ResultT m) = runExceptT m\n
Run Code Online (Sandbox Code Playgroud)\n当然,还可以派生出更多实例,但不是全部。Alternative
并MonadPlus
有丑陋的行为。
无论如何,这是一个足够常见的问题,需要有适当的可重用解决方案来解决。这是使用 monad 转换器处理它的方式FailT
:
\xce\xbb> import Control.Monad.Trans.Fail.String (runFailT)\n\xce\xbb> runFailT (myFunc (pure (Expected "Totally fine")))\nRight "\\"Totally fine\\""\n\xce\xbb> runFailT (myFunc (pure (Unexpected "Surprise!")))\nLeft "Pattern match failure in \'do\' block at /home/lehins/github/public/haskell/stackoverflow/errort-is-deprecated-but-exceptt-doesnt-fit/src/Lib.hs:25:3-12"\n
Run Code Online (Sandbox Code Playgroud)\n对于任何对这个主题感兴趣的人,我还写了一篇关于它的完整博客文章:Fail with class。
\n