haskell 将MonadError与可能基于IO的transformers一起使用

okxuctiv  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(128)

如何将MonadError用于Transformer堆栈中的错误处理,这些堆栈可能基于IO,也可能不基于IO
我想使用来自MonadError(在mtl中)的throwErrorcatchError来处理monad Transformer堆栈中的故障。堆栈的基础可能是IO或其他类似Either e的东西(其中e是某种错误类型)。我觉得这应该是可能的,而不添加一个ExceptT层。
然而,我不知道如何以一种既适用于IO又适用于其他可能的基的方式实现它。IOMonadError示例被定义为MonadError IOException IO,这将错误类型限制为IOException。当然,如果堆栈中没有IO monad,这就没有意义了。使用不同的错误类型会破坏IO
例如,考虑这个函数(在这里使用Contexts):

f :: MonadError String m => Int -> ReaderT r m ()
f 0 = throwError "This is an error."
f n = return ()

runReaderT (f 1) 0 :: Either String ()的计算结果为Right (),但runReaderT (f 1) 0 :: IO ()给出了一个错误:

• Couldn't match type ‘GHC.IO.Exception.IOException’ with ‘[Char]’
        arising from a functional dependency between:
          constraint ‘MonadError String IO’ arising from a use of ‘f’
          instance ‘MonadError GHC.IO.Exception.IOException IO’
            at <no location info>
    • In the first argument of ‘runReaderT’, namely ‘(f 1)’
      In the expression: runReaderT (f 1) 0 :: IO ()
      In an equation for ‘it’: it = runReaderT (f 1) 0 :: IO ()

我尝试为IO编写一个替代的MonadError示例,它使用String错误,但似乎MonadError有一个函数依赖,这使得这是不可能的。

hk8txs48

hk8txs481#

一种选择是创建一个StringIOException都是其示例的类,并在抛出时使用它。

{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
import GHC.IO.Exception
import Control.Monad.Reader
import Control.Monad.Except

class StringException a where stringException :: String -> a
instance StringException IOException where stringException = userError
instance StringException String where stringException = id

f :: (StringException e, MonadError e m) => Int -> ReaderT r m ()
f 0 = throwError (stringException "yikes")
f n = pure ()

main = do
    print (runReaderT (f @String @(Either _) 1) 0)
    runReaderT (f 1) 0

相关问题