试图了解用于处理IO
内部可能出现的故障的模式。如果它只是一个case
,如下所示,那可能是可以接受的,但是如果嵌套继续进行一堆嵌套的IO (Either String Int)
,则存在一种通用的模式来处理此类类型。例如,如果b
中的functionDoSomething
再次是(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 ()
答案 0 :(得分:3)
我了解您是Haskell的新手,而monad变压器并不是您想要解决的第一个概念。在这种情况下,是,但是使用的是模式。
一般说来,单子使您能够“编织进出函子”。如果只有Either
,则可以使用Either
值和do
表示法,将Right
值从值中拉出,同时使{{1 }}个案例。
但是,在这种情况下,您在Left
内有一个“堆栈”的monad:Either
。因此,当您尝试使用IO
表示法时,您就处在do
上下文中,这意味着,正如OP所说明的那样,您可以使用IO
箭头仍然是<-
值。
Monad转换器使您可以将Monad堆栈(例如,在Either
内的Either
值)视为IO
实例,以便可以使用{{ 1}}符号在堆栈上。
虽然您期望Monad
monad变压器被称为do
,但由于各种原因,它却被称为Either
。您可以像这样稍微简化OP代码:
EitherT
此处,ExceptT
是一个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
。