处理 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
except
将 Either err b
变为 Monad m => ExceptT err m b
,然后您可以在 ExceptT err (ST s)
monad 中执行其他所有操作。
作为一般规则,ExceptT
是处理单子动作的好方法,当您通常 想在失败时放弃时,这些动作可能会失败。主要的例外是当底层 monad 是 IO
时,在这种情况下更常见的是使用来自 Control.Exception
.
的内置异常功能
当然,如果你只需要一个 monadic bind,ExceptT
似乎有点矫枉过正,但一旦你需要更多,它绝对有意义。
假设我有以下功能:
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
except
将 Either err b
变为 Monad m => ExceptT err m b
,然后您可以在 ExceptT err (ST s)
monad 中执行其他所有操作。
作为一般规则,ExceptT
是处理单子动作的好方法,当您通常 想在失败时放弃时,这些动作可能会失败。主要的例外是当底层 monad 是 IO
时,在这种情况下更常见的是使用来自 Control.Exception
.
当然,如果你只需要一个 monadic bind,ExceptT
似乎有点矫枉过正,但一旦你需要更多,它绝对有意义。