【问题标题】:Haskell: Common pattern to deal with Failure inside IO :: IO (Either String Int) [duplicate]Haskell:处理 IO :: IO (Either String Int) 内部失败的通用模式 [重复]
【发布时间】:2019-01-31 15:14:51
【问题描述】:

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


    【解决方案1】:

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

    可以说,Monad 通常可以让您“穿入和穿出函子”。如果您只有Either,您可以使用Either 值和do 表示法将Right 值从值中提取出来,同时短路Left 案例。

    但是,在这种情况下,您有一个“堆栈”单子:EitherIO 内部。因此,当您尝试使用 do 表示法时,您处于 IO 上下文中,这意味着,正如 OP 所示,您使用 &lt;- 箭头“拉出”函数的值, 仍然是 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

    【讨论】:

    • IO (Either String ()) 也是ExceptT String IO (),对吧?
    • @chepner 它们是两种不同的类型,但它们是同构的。 ExceptT 走一条路,runExceptT 走另一条路。
    • @chepner ExceptTnewtype,所以从某种意义上说你是对的。
    • 啊,是的,我明白了。
    猜你喜欢
    • 2011-05-23
    • 2014-06-02
    • 1970-01-01
    • 2012-05-13
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多