Haskell: IO :: IO (Either String Int) 内部处理失败的通用模式

Haskell: Common pattern to deal with Failure inside IO :: IO (Either String Int)

试图了解用于处理内部可能故障的模式 IO。如果它只是一个像下面这样的 cases,它可能是可以接受的,但是如果嵌套继续进行一堆嵌套的 IO (Either String Int)s 是否有处理此类类型的通用模式。例如,如果 functionDoSomething 中的 b 又是一个 (Either a b) 并且在成功时获取值并再次用它做某事将是另一个这样的 case。我可以使用更高阶的函数吗?我对 monad 转换器还不太满意,不确定它们是否可以用来处理这个特定的 monad 堆栈。如果它们可以在这里使用,有没有不用它们的方法。

import Control.Monad

functionCreate :: Int -> IO (Either String Int)
functionDoSomething :: Int -> IO b

functionUse :: IO ()
functionUse = do
   created <- functionCreate 10
   case created of
      (Right v)        -> void $ functionDoSomething v
      _                -> return ()

我知道您是 Haskell 的新手,并且 monad 转换器不是您想要解决的第一个概念。在这种情况下,它 ,但是,要使用的模式。

一般来说,Monad 可以让你 'weave in and out of functors',可以这么说。如果您只有 Either,您可以使用带有 do 符号的 Either 值将 Right 值从值中拉出,同时将 [=15] 短路=] 例。

然而,在这种情况下,您有一个 'stack' 个单子:EitherIO 内。因此,当您尝试使用 do 表示法时,您处于 IO 上下文中,这意味着,正如 OP 所示,您 'pull out of' 函数的值,使用<- 箭头,仍然是 Either 值。

Monad 转换器使您能够将 monad 堆栈(例如,在本例中 IO 内的 Either 值)视为 Monad 个实例,这样您就可以,例如,使用do 堆栈上的符号。

虽然您希望 Either monad 转换器被称为 EitherT,但由于各种原因,它被称为 ExceptT。您可以像这样稍微简化 OP 代码:

import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except

functionUse :: IO (Either String ())
functionUse = runExceptT $ do
  created <- ExceptT $ functionCreate 10
  liftIO $ void $ functionDoSomething created

这里,created是一个Int值,然后可以传递给functionDoSomething