假设我具有以下功能:

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的返回值包装在另一个状态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绑定,ExceptT似乎有点过大了,但是一旦您需要更多,它肯定是有道理的。

10-08 12:36
查看更多