如何将多个 monad 效果组合到同一个 do 块中?

How to combine multiple monad effects into the same do block?

我有一个函数调用 IO 类型的函数和 Either String a 类型的函数。

我想在 do 符号中合并效果,以便我可以在必要时解包 IO,同时在遇到第一个 Left 时中止计算。

这是一个非常简单的例子,你能帮我解决一下吗? (使用 runEitherT 是可选的。但我认为如果你使用 plain either,你将无法使用 MonadErrorMonadIO 功能)。

entryPoint :: IO (Either String Int)
entryPoint = runEitherT foo

-- p and p' should have type Int,
-- and errorf can force the computation to abort (as can throwError) 
foo :: EitherT String IO Int
foo = do
  p <- liftIO $ iof 1
  p' <- return $ errorf p
  if p' == 2
    then throwError "No!"
    else return 1

errorf :: b -> Either String b
errorf = undefined

iof :: a -> IO a
iof = undefined

部分

p' <- return $ errorf p

看起来不对。这里,returnEitherT String IO 中构建了一个 monadic 值。假设 errorf p = Left something 正在构建的值是

p' <- EitherT (return (Right (Left something)))

上面的 return 构建了一个 IO 动作。这不是我们想要的——那里有一个额外的 Right。我们反而想要

p' <- EitherT (return (Left something))

也就是

p' <- EitherT $ return $ errorf p