ErrorT 已弃用,但 ExceptT 不适合

JB.*_*JB. 6 haskell

我有一个一元计算。在某些时候,由于 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没有。

我的非弃用选项是什么?

leh*_*ins 0

这个问题问得好!我什至编写了一个实际的库FailT来解决这个优雅失败的问题MonadFail

\n

我不确定确切的设置是什么,但我想用一个具体的例子来回答这个问题。假设我们有一个单子动作接受另一个产生的单子动作MyType,我们可以打赌我们的家庭农场会是这种Expected情况:

\n
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)\n

base不幸的是,在或其他与 GHC 连接的库中没有合适的解决方案,例如transformersmtl

\n

就像你已经知道的那样ErrorT这本来可以完美地实现这一点,但出于充分的理由,它已被弃用。

\n

ExceptT本来可以提供一个合理的MonadFail实例,但这对于向后兼容性来说是相当有问题的。

\n

正如评论中所建议的那样,ExceptT用 a包裹起来newtype并提供自定义MonadFail实例肯定会起作用,但是谁希望每次遇到此问题时都将其包含在代码库中。为了完整起见,这里是一个最小的独立解决方案:

\n
{-# 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

当然,还可以派生出更多实例,但不是全部。AlternativeMonadPlus有丑陋的行为。

\n

无论如何,这是一个足够常见的问题,需要有适当的可重用解决方案来解决。这是使用 monad 转换器处理它的方式FailT

\n
\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