我有一组用户,组以及用户和组之间的映射。我有各种操作这些集合的函数,但是不应该为不存在的用户添加用户< - >组映射,也不能删除仍然将用户作为成员的组等。
所以基本上我希望这些函数抛出必须由调用者明确处理的“异常”。
我首先想到的是返回这样的东西:
data Return r e = Success r | Exception e
如果调用者未能与Exception
进行模式匹配,他们将希望获得编译器警告,或者在出现问题时至少会出现明显的运行时错误。
这是最好的方法,是否有预先打包的解决方案?注意我需要抛出并捕获纯代码中的“异常”,而不是IO Monad。
答案 0 :(得分:19)
是的,这是一种很好的方法,它位于标准库中:Return r e
与Either e r
相同。您甚至可以编写代码,就像在IO
中使用异常一样(即,无需使用模式匹配在每个步骤中显式处理错误):Monad
Either
实例传播错误,就像Maybe
monad一样(但在出现错误的情况下附加e
值)。例如:
data MyError
= Oops String
| VeryBadError Int Int
mightFail :: T -> Either MyError Int
mightFail a = ...
foo :: T -> T -> Int -> Either MyError Int
foo a b c = do
x <- mightFail a
y <- mightFail b
if x == y
then throwError (VeryBadError x y)
else return (x + y + c)
如果mightFail a
或mightFail b
返回Left someError
,那么foo a b c
也会;错误会自动传播。 (在这里,throwError
只是使用Control.Monad.Error
中的函数编写Left
的好方法;还有catchError
来捕获这些异常。)
答案 1 :(得分:11)
您描述的Return r e
类型正是标准类型
data Either a b = Left a | Right b
您可能希望使用mtl包的所谓"error monad"(更合适的名称是“exception monad”)。 (或者,如果您不想使用mtl,则monadLib包中有ExceptionT
。这允许您通过调用throwError
和catchError
在纯代码中进行错误处理。
Here您可以找到一个展示如何使用它的示例。