haskell - 在变压器堆栈的底部插入 ErrorT

标签 haskell error-handling monads monad-transformers

运行类型为 t (ErrorT String IO) a 的代码的最佳方式是什么?来自 t IO a单子(monad)?考虑下面的代码:

module Sample where

import System.IO
import Control.Monad.Reader
import Control.Monad.Error

type Env = String

inner :: ReaderT Env (ErrorT String IO) ()
inner = do
    s <- ask
    fail s

outer :: ReaderT Env IO ()
outer = do
    env <- ask
    res <- lift $ runErrorT $ runReaderT inner env
    case res of
        Left err -> liftIO $ hPutStrLn stderr err
        Right _ -> return ()
    outer

这可行,但我一直在寻找一种更优雅的方式在我的堆栈底部插入 ErrorT。特别是我在我的项目中使用了几个不同的 monad 转换器堆栈,并且为每个堆栈编写上面的内容非常乏味。

我正在寻找类似的东西:
outer :: ReaderT Env IO ()
outer = do
    res <- (hoist runErrorT) inner
    ...

但我不能使用 hoist由于类型不匹配。

编辑:

我用 StateT在我的一些堆栈中,这就是尝试放置 ErrorT 的原因在底部而不是顶部。
outer应该是一个无限循环。

最佳答案

请注意,正如 Edward 所说,将 ErrorT在堆栈的顶部,而不是底部。

这可以改变堆栈的语义,至少对于比 ReaderT 更复杂的转换器。 - 例如如果你有 StateT在堆栈中,然后使用 ErrorT底部的更改将在出现错误时回滚,而 ErrorT在顶部,发生错误时将保留对状态的更改。

如果你真的需要它在底部,那么这样的事情会通过类型检查器:

import Control.Monad.Error
import Control.Monad.Morph
import System.IO

toOuter :: MFunctor t => t (ErrorT String IO) a -> t IO a
toOuter = hoist runErrorTWithPrint

runErrorTWithPrint :: ErrorT String IO a -> IO a
runErrorTWithPrint m = do
   res <- runErrorT m
   case res of
       Left err -> do
           hPutStrLn stderr err
           fail err
       Right v -> return v

请注意,它调用 fail当内部计算失败时,这不是您上面的代码所做的。

主要原因是要使用hoist我们需要提供 forall a . ErrorT String IO a -> IO a 类型的函数- 即处理任何类型的值,而不仅仅是 () .这是因为取决于 monad 堆栈的其余部分可能意味着当您到达 ErrorT 时的实际返回类型。与您开始使用的返回类型不同。

在失败的情况下,我们没有 a 类型的值。所以一种选择是失败。

在您的原始代码中,您还可以无限循环 outer ,这是不行的。

关于haskell - 在变压器堆栈的底部插入 ErrorT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20726214/

相关文章:

haskell - Haskell 如何废弃样板文件?

haskell - 实现相同功能的不同类型的映射列表?

haskell - 在 SML 中编码 rank-2 多态性等价物

javascript - 如何从 NetSuite 中的 RESTlet 引发自定义错误?

c# - 在多个例程之间使用try-catch

c - 处理函数错误消息的最佳方式?

haskell - 实例 Monoid Monad

haskell - 运行管道的基本 monad

haskell - 如何有条件地绑定(bind)在 do block 中?

Scalaz Bind[Seq] 类型类