Pregunta

Si nos fijamos en el ejemplo de catches:

 f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
                     Handler (\ (ex :: IOException)    -> handleIO    ex)]

Parece que catches ha definido un mecanismo de medida para adecuarse a los patrones (los dos tipos de excepciones). ¿Estoy equivocado, o puede esto ser generalizado para permitir que uno de definir una función que puede tener funciones lambda que coinciden en un cierto patrón?

Editar: Para su información a continuación es la fuente GHC para las capturas. Si alguien puede arrojar algo de luz sobre cómo funciona esto sería muy bueno.

catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers

catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
    where tryHandler (Handler handler) res
              = case fromException e of
                Just e' -> handler e'
                Nothing -> res
¿Fue útil?

Solución

Esta es la Scoped variables de tipo extensión GHC en el trabajo. Sigue el enlace para obtener más información.

Básicamente, se define una afirmación acerca del tipo que tienen que ser cumplidos por el golpeteo antes de que pueda igualar. Así que, sí, es similar a los guardias, pero no del todo.

Como funciona este ejemplo en particular? Buceo en fuentes de "base" de la biblioteca para descubrir que:

class (Show e) => Exception e where
    toException   :: e -> SomeException
    fromException :: SomeException -> Maybe e

data SomeException = forall e . Exception e => SomeException e

instance Exception IOException where
    toException = IOException
    fromException (IOException e) = Just e
    fromException _ = Nothing

instance Exception ArithException where
    toException = ArithException
    fromException (ArithException e) = Just e
    fromException _ = Nothing

Vemos que IOException y ArithException diferentes tipos de aplicación de la Exception clase de tipos. También vemos que toException/fromException es un envasado / desenvolver mecanismo que permite convertir valores de tipo Exception a / de valores de tipos IOException, ArithException, etc.

Por lo tanto, podríamos haber escrito:

f = expr `catches` [Handler handleArith,
                    Handler handleIO]

handleArith :: ArithException -> IO ()
handleArith ex = ....

handleIO :: IOException -> IO ()
handleIO ex = ....

Supongamos que IOException sucede. Cuando catchesHandler procesa primer elemento de la lista de controladores, que llama tryHandler, que llama fromException. De la definición de tryHandler se deduce que el tipo de retorno de la fromException debe ser el mismo que el argumento de handleArith. Por otro lado, e es del tipo de excepción, es decir, - (IOException ...). Por lo tanto, los tipos juegan de esta manera (esto no es una Haskell válida, pero espero que mi punto):

fromException :: (IOException ...) -> Maybe ArithException

Desde el instance Exception IOException ... se deduce inmediatamente que el resultado es Nothing, por lo que este controlador se salta. Por el mismo razonamiento el siguiente controlador sería llamado, porque fromException volvería (Just (IOException ...)).

Por lo tanto, usted ha utilizado las firmas de tipos de handleArith y handleIO para especificar cuando cada uno de ellos se llamaría, y fromException/toException se aseguró de que haya sucedido de esta manera.

Si lo desea, usted podría también constreñimiento tipos de handleIO y handleArith dentro de la definición de f, utilizando variables de tipo con ámbito. Podría decirse que esto podría darle una mejor lectura.

La finalización, con ámbito variables de tipo no son unas primarias jugadores aquí. Ellos sólo se utilizan por conveniencia. máquinas principales para la reproducción de este tipo de trucos es fromException/toException y amigos. Las variables de tipo de ámbito simplemente le permiten tener la sintaxis que se asemejan más a los patrones de guardia.

Otros consejos

case () of 
  ()| foo expr1 -> handleFooCase
    | bar expr2 -> handleBarCase
    | otherwise -> blah
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top