Haskell:处理 IO 内部故障的常见模式 :: IO (Either String Int)

que*_*eue 4 monads haskell

试图了解用于处理内部可能出现的故障的模式IO。如果它只是case像下面这样的 s,它可能是可以接受的,但是如果对一堆嵌套的IO (Either String Int)s进行嵌套,是否有处理此类类型的通用模式。例如,如果binfunctionDoSomething再次是 a(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 ()
Run Code Online (Sandbox Code Playgroud)

Mar*_*ann 6

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

可以这么说,Monads 通常使您能够“织入和织出函子”。如果您只有Either,您可以使用Eitherdo符号的Right值将值从值中提取出来,同时使Left情况短路。

但是,在这种情况下,您有一堆 monad:EitherIO. 因此,当您尝试使用do符号时,您处于IO上下文中,这意味着,正如 OP 所示,您使用<-箭头从函数中“拉出”的Either值仍然是值。

Monad 转换器使您能够将 monad 堆栈(例如,在这种情况下,Either内部的值IO)视为Monad实例,以便您可以,例如,do在堆栈上使用符号。

虽然您希望Eithermonad 转换器被称为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
Run Code Online (Sandbox Code Playgroud)

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