假设我具有以下功能:
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
except
将Either err b
转换为Monad m => ExceptT err m b
,然后您可以在ExceptT err (ST s)
monad中执行其他所有操作。通常,
ExceptT
是处理单子动作的好方法,这些单子动作通常在您要为失败保释时可能会失败。主要的例外是当底层monad为IO
时,在这种情况下,更常见的是使用Control.Exception
中的内置例外功能。当然,如果只需要一个monadic绑定,
ExceptT
似乎有点过大了,但是一旦您需要更多,它肯定是有道理的。