试图理解用于处理IO
内部可能故障的模式。如果它只是像下面这样的一个case
,它可能可以接受,但如果嵌套一堆嵌套IO (Either String Int)
继续下去,是否有一种通用模式来处理此类类型。例如,如果functionDoSomething
中的b
再次成为一种(Either a b)
,并且获得成功的价值并再次使用它将是另一种case
。我可以使用高阶函数吗?我还不熟悉单子变压器,不确定它们是否可以用来处理这个特定的单子堆栈。如果它们可以在这里使用,有没有办法在不使用它们的情况下做到这一点。
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变压器并不是你想要解决的第一个概念。然而,在这种情况下,它是要使用的模式。
可以这么说,Monads 通常使您能够"编织进进出函子"。如果你只有Either
,你可以使用带有do
符号的Either
值从值中提取Right
值,同时短路Left
情况。
但是,在这种情况下,您有一堆monads:Either
IO
内部。因此,当您尝试使用do
表示法时,您处于IO
上下文中,这意味着,如 OP 所示,您使用<-
箭头从函数中"拉出"的值仍然是Either
值。
Monad 转换器使您能够将 monad 堆栈(例如,在本例中Either
IO
中的值(视为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
。