Woj*_*ski 4 error-handling monads haskell monad-transformers
t (ErrorT String IO) a在t IO amonad中运行带有类型的代码的最佳方法是什么?请考虑以下代码:
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
Run Code Online (Sandbox Code Playgroud)
这有效,但我一直在寻找一种更优雅的方式在我的堆栈底部插入ErrorT.特别是我在我的项目中使用了几个不同的monad变换器堆栈,并且为每个变换器堆栈编写上面的内容非常繁琐.
我在寻找类似的东西:
outer :: ReaderT Env IO ()
outer = do
res <- (hoist runErrorT) inner
...
Run Code Online (Sandbox Code Playgroud)
但hoist由于类型不匹配,我无法使用.
编辑:
我StateT在我的一些堆栈中使用,这就是尝试放在ErrorT底座而不是顶部的原因.
本outer应该是一个无限循环.
请注意,正如爱德华所说,将它放在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
Run Code Online (Sandbox Code Playgroud)
请注意,它fail在内部计算失败时调用,这不是您上面的代码所做的.
主要原因是使用hoist我们需要提供类型的函数forall a . ErrorT String IO a -> IO a- 即处理任何类型的值,而不仅仅是().这是因为取决于monad堆栈的其余部分可能意味着当您到达时的实际返回类型ErrorT与您开始时的返回类型不同.
在失败的情况下,我们没有类型的值,a因此一个选项是失败.
在原始代码中,您也可以无限循环outer,这是不可行的.
这里正确的答案是"不要那样做".
这里的问题是你正在挑选分层.如果你移到Error外面,它会fail在这种情况下表现得很好.一般认为变压器堆栈是某种量子波形,直到最后一分钟才能崩溃.
inner :: MonadReader Env m => m ()
inner = do
s <- ask
fail s
outer :: (MonadReader Env m, MonadIO m) => m ()
outer = do
res <- runErrorT inner
case res of
Left err -> liftIO $ hPutStrLn stderr err
Right _ -> return ()
outer
Run Code Online (Sandbox Code Playgroud)
注意一切都变得多么简单.没有吊装,没有明确的提升,虚无... inner在不同的monad中运行,我们已经扩展了当前的monad,无论它是什么,外部都有ErrorT.
如果不明确选择堆栈,则可以最大化可以使用代码的情况数.
如果你绝对必须这样做,那么请遵循Ganesh的路径,但要认真思考你是否真的需要在你描述的情况下变形!
| 归档时间: |
|
| 查看次数: |
218 次 |
| 最近记录: |