2012-05-16 12 views
14

Tengo un conjunto de usuarios, grupos y un mapeo entre usuarios y grupos. Tengo varias funciones que manipulan estos conjuntos, sin embargo, uno no debería poder agregar un usuario < -> asignación de grupo para un usuario que no existe, ni eliminar un grupo que todavía tiene usuarios como miembros, etc.Haskell "excepciones"

Así básicamente quiero que estas funciones arrojen "excepciones" que deben ser tratadas explícitamente por la persona que llama.

pensé por primera vez de devolver algo como esto:

data Return r e = Success r | Exception e 

Y si la persona que llama no coincidencia de patrones en contra de la Exception, es de esperar que obtendrá una advertencia del compilador, o por lo menos tener un tiempo de ejecución obvia error cuando hay un problema

¿Es este el mejor enfoque, y hay una solución preempaquetada que hace esto? Tenga en cuenta que necesito lanzar y atrapar "excepciones" en código puro, no en IO Monad.

Respuesta

19

Sí, este es un buen enfoque, y está en la biblioteca estándar: Return r e es lo mismo que Either e r. Incluso puede escribir código como lo haría utilizando excepciones en IO, también (es decir, sin tener que manejar explícitamente los errores en cada paso con coincidencia de patrón): la instancia Monad para Either propaga los errores, al igual que la mónada Maybe (pero con valor adicional e en el caso de un error). Por ejemplo:

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) 

Si mightFail a o mightFail b vuelve Left someError, entonces foo a b c también lo hará; los errores se propagan automáticamente (Aquí, throwError es sólo una buena manera de escribir Left, utilizando las funciones de Control.Monad.Error, también hay catchError para atrapar estas excepciones.)

11

El tipo Return r e que usted está describiendo es exactamente el tipo estándar

data Either a b = Left a | Right b 

Es posible que desee utilizar el llamado "error monad" (un nombre más adecuado es "excepción mónada") del paquete mtl. (Alternativamente, hay ExceptionT en el paquete monadLib si no desea usar mtl.) Esto le permite realizar el manejo de errores en código puro invocando throwError y catchError. Here puede encontrar un ejemplo que muestra cómo usarlo.