Esta es la extensión Scoped Type Variables GHC en el trabajo. Sigue el enlace para obtener más información.
Básicamente, define una afirmación sobre el tipo que debe cumplir el patrón antes de que pueda coincidir. Entonces, sí, es similar a los guardias, pero no del todo.
¿Cómo funciona este ejemplo en particular? Sumergirse en sources of "base" library 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
son diferentes tipos de aplicación de la clase de tipos Exception
. También vemos que es una toException/fromException
/dispositivo de enrollado desenvolver que permite convertir valores de tipo Exception
a/de valores de tipos IOException
, ArithException
, etc.
Así, podríamos haber escrito:
f = expr `catches` [Handler handleArith,
Handler handleIO]
handleArith :: ArithException -> IO()
handleArith ex = ....
handleIO :: IOException -> IO()
handleIO ex = ....
Supongamos que ocurre IOException
. Cuando catchesHandler
procesa el primer elemento de la lista de controladores, llama al tryHandler
, que llama al fromException
. De la definición de tryHandler
se deduce que el tipo de retorno de fromException
debe ser el mismo que el argumento de handleArith
. Por otro lado, e
es del tipo Excepción, a saber - (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 se llamaría al siguiente controlador, porque fromException
devolverí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 aseguraron de que haya sucedido de esta manera.
Si lo desea, también puede restringir los tipos de handleIO
y handleArith
dentro de la definición de f
, utilizando variables de tipo de ámbito. Podría decirse que esto podría darte una mejor legibilidad.
Finalización, tipo de ámbito Las variables no son un jugador principal aquí. Solo se usan por conveniencia. La maquinaria principal para jugar este tipo de trucos es fromException/toException
y amigos. Las variables de tipo con alcance solo le permiten tener una sintaxis que se asemeja más a los patrones de protección.
¿Cómo se involucran las variables de tipo de ámbito? No veo que este mecanismo funcione en la fuente de las capturas. – me2
Actualizado para explicar fromException/toException trickery – ADEpt