处理 Either 和 ST 单子

Handling Either and ST monads

假设我有以下功能:

checkA :: a -> Either err b
checkA = undefined

checkB :: b -> ST s (Either err c)
checkB = undefined

check :: a -> ST s (Either err c)
check a = either (return . Left) checkB (checkA a)

有没有什么方法可以编写 check,这样它就不需要使用 return . Left?通常我会做类似 >>= 的事情,但在这种情况下 checkB 的 return 被包装在另一个状态 monad 中,所以它不起作用。另一个约束是 checkB 应该只 运行 如果 checkA a 评估为 Right,并且应该只是失败并在 Left

上出现错误

总而言之,是否有使用嵌套 monad 的标准方法?

这是使用 ExceptT 的一种方法:

checkA :: a -> Either err b
checkA = undefined

checkB :: b -> ExceptT err (ST s) c
checkB = undefined

check :: a -> ExceptT err (ST s) c
check a = except (checkA a) >>= checkB
-- or
check = except . checkA >=> checkB

exceptEither err b 变为 Monad m => ExceptT err m b,然后您可以在 ExceptT err (ST s) monad 中执行其他所有操作。

作为一般规则,ExceptT 是处理单子动作的好方法,当您通常 想在失败时放弃时,这些动作可能会失败。主要的例外是当底层 monad 是 IO 时,在这种情况下更常见的是使用来自 Control.Exception.

的内置异常功能

当然,如果你只需要一个 monadic bind,ExceptT似乎有点矫枉过正,但一旦你需要更多,它绝对有意义。