试图了解用于处理内部可能出现的故障的模式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)
我知道您是 Haskell 的新手,并且 monad 转换器不是您想要解决的第一个概念。然而,在这种情况下,它是要使用的模式。
可以这么说,Monads 通常使您能够“织入和织出函子”。如果您只有Either,您可以使用Either带do符号的Right值将值从值中提取出来,同时使Left情况短路。
但是,在这种情况下,您有一堆 monad:Either在IO. 因此,当您尝试使用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。