error-handling - EitherT 是如何工作的?

标签 error-handling monad-transformers haskell either

我花了半天时间试图弄清楚如何使用 EitherT 来处理我的代码中的错误。

我已经定义了一个这样的变压器堆栈。

-- Stuff Monad

data StuffConfig = StuffConfig {
  appId     :: T.Text,
  appSecret :: T.Text
}

data StuffState = StuffState {
  stateToken :: Maybe Token,
  stateTime  :: POSIXTime
}

newtype Stuff a = Stuff {
  runStuff :: (ReaderT StuffConfig (StateT StuffState (EitherT T.Text IO))) a
} deriving (Monad, Functor, Applicative, 
            MonadIO, 
            MonadReader StuffConfig,
            MonadState StuffState
            )



askStuff :: StuffConfig -> Stuff a -> IO (Either T.Text a)
askStuff config a = do
  t <- getPOSIXTime 
  runEitherT (evalStateT (runReaderT (runStuff a) config) (StuffState Nothing t))

只要我只使用 ReaderT 就可以很好地工作和 StateT功能。我的印象是现在我应该能够写出这样的东西:
faultyFunction :: String -> Stuff String
faultyFunction s = do
  when s == "left" $ left "breaking out"
  "right"

更重要的是捕获 Either hoistEither 应有的返回值来自 errors包裹:
faultyLookup :: Map -> String -> Stuff String
faultyLookup m k = do
  hoistEither $ lookup k m

我阅读了关于单子(monad)更改器(mutator)的真实世界haskell章节并摆弄了lift .但是我无法进行任何类型检查。

最佳答案

不能只使用 left 的原因和 hoistEitherStateT 不同的是,直接功能和 ReaderT来自 mtl 包, either 包不提供类似于 MonadReader 的类型类或 MonadState .

上述类型类负责透明地提升 monad 堆栈,但对于 EitherT ,您必须自己完成提升(或编写类似于 MonadEither 等的 MonadReader 类型类)。

faultyFunction :: String -> Stuff String
faultyFunction s = do
  when (s == "left") $ Stuff $ lift $ lift $ left "breaking out"
  return "right"

首先你需要申请Stuff包装器,然后是 lift超过 ReaderT变压器,然后 lift再次通过StateT变压器。

您可能想为自己编写实用程序函数,例如
stuffLeft :: T.Text -> Stuff a
stuffLeft = Stuff . lift . lift . left

然后你可以像这样简单地使用它:
faultyFunction :: String -> Stuff String
faultyFunction s = do
  when (s == "left") $ stuffLeft "breaking out"
  return "right"

或者,您可以使用 Control.Monad.Error 来自 mtl , 如果您定义 Error Text 的实例.
instance Error T.Text where
  strMsg = T.pack

现在您可以更改 Stuff 的定义实现lefthoistEither像这样:
newtype Stuff a = Stuff {
  runStuff :: (ReaderT StuffConfig (StateT StuffState (ErrorT T.Text IO))) a
} deriving (Monad, Functor, Applicative,
            MonadIO,
            MonadReader StuffConfig,
            MonadState StuffState,
            MonadError T.Text
            )

left :: T.Text -> Stuff a
left = throwError

hoistEither :: Either T.Text a -> Stuff a
hoistEither = Stuff . lift . lift . ErrorT . return

有了这个你原来的faultyFunction无需任何手动提升即可进行型式检查。

您还可以为 left 编写通用实现。和 hoistEither适用于 MonadError 的任何实例(使用 either 来自 Data.Either ):
left :: MonadError e m => e -> m a
left = throwError

hoistEither :: MonadError e m => Either e a -> m a
hoistEither = either throwError return

关于error-handling - EitherT 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14428756/

相关文章:

wcf - 如何在未处理的错误时停止自托管 WCF 服务?

error-handling - 在Silex中使用错误处理程序时,如何渲染 Twig 模板?

objective-c - 对象在 iOS5 上被释放,但在 iOS4 上没有。如何追踪?

haskell - 将惰性字节字符串转换为严格字节字符串

C编程读取输入错误检查

haskell - 使用 ReaderT Maybe 还是 MaybeT Reader?

Scala:从猫中创建自定义 OptionT monad 进行学习

haskell - 在haskell程序中使用返回的EitherT

haskell - 使用 PolyKinds 和类型系列时出现类型歧义

haskell - pandoc 中缺少链接和其他类型元素的属性