我的代码结构如下例所示。我很确定应该有一种方法来更合理地构建它。我会假设任何(或错误)monad 可以提供帮助,但我不知道从哪里开始。有什么指示可以让我朝着正确的方向前进吗?
data Data1 = Data1 { d2Id :: String }
data Data2 = Data2 { d3Id :: String }
data Data3 = Data3 { d4Id :: String }
getData1 :: String -> IO (Either String Data1)
getData2 :: String -> IO (Either String Data2)
getData3 :: String -> IO (Either String Data3)
process :: Data1 -> Data2 -> Data3 -> IO ()
get :: String -> IO ()
get id = do
r1 <- getData1 id
case r1 of
Left err -> print err
Right d1 -> do
r2 <- getData2 $ d2Id d1
case r2 of
Left err -> print err
Right d2 -> do
r3 <- getData3 $ d3Id d2
case r3 of
Left err -> print err
Right d3 -> do
process d1 d2 d3
最佳答案
我正在重新打开这个问题,因为我认为看到它会有所帮助
如何转换这种特定的代码。
我们需要一些导入:
import Control.Monad.Trans
import Control.Monad.Trans.Either
然后通过将
get
应用于每个通过返回 EitherT
发出错误信号的 IO-action 来转换您的 Either
函数:-- get' :: EitherT String IO ()
get' id = do
d1 <- EitherT $ getData1 id
d2 <- EitherT $ getData2 (d2Id d1)
d3 <- EitherT $ getData3 (d3Id d2)
liftIO $ process d1 d2 d3
请注意,我们不将
EitherT
用于 process
。相反,我们使用 liftIO
因为 process
不会发出错误信号。GHC 应该能够推断类型签名,因此您不需要提供它。
要运行新版本,请使用
runEitherT
,它将在 IO-monad 中返回一个 Either
值:doit :: String -> IO ()
doit id = do
res <- runEitherT (get' id)
case res of
Left err -> print err
Right d -> return ()
关于haskell - 如何避免案件金字塔?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37796211/