14

我有一组用户、组以及用户和组之间的映射。我有各种操作这些集合的函数,但是不能为不存在的用户添加用户<->组映射,也不能删除仍然有用户作为成员的组等。

所以基本上我希望这些函数抛出必须由调用者明确处理的“异常”。

我首先想到的是返回这样的东西:

data Return r e = Success r | Exception e

如果调用者未能与Exception.

这是最好的方法吗,是否有一个预先打包的解决方案可以做到这一点?注意我需要在纯代码中抛出和捕获“异常”,而不是 IO Monad。

4

2 回答 2

19

是的,这是一个很好的方法,它在标准库中:Return r eEither e r. 您甚至可以像在 中使用异常一样编写代码IO(即,不必在每个步骤中使用模式匹配显式处理错误):Monadfor 的实例Either传播错误,就像Maybemonad 一样(但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 aormightFail b返回Left someError,那么foo a b c也会;错误会自动传播。(在这里,throwError这只是一种很好的编写方式Left,使用来自 的函数Control.Monad.Error;还有catchError捕获这些异常的方法。)

于 2012-05-16T02:59:01.323 回答
11

您描述的Return r e类型正是标准类型

data Either a b = Left a | Right b

您可能希望使用 mtl 包的所谓“错误单子”(更合适的名称是“异常单子”)。(或者,ExceptionT如果您不想使用 mtl,则可以在 monadLib 包中。)这允许您通过调用throwError和来在纯代码中进行错误处理catchError在这里您可以找到一个示例来说明如何使用它。

于 2012-05-16T03:04:15.503 回答