Haskell:处理IO内部故障的通用模式:: IO(任意一个字符串整数)

时间:2018-08-25 10:25:58

标签: haskell monads

试图了解用于处理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 ()

1 个答案:

答案 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