Questa è l'estensione GH2 Scoped Type Variables al lavoro. Segui il link per saperne di più.
Fondamentalmente, si definisce un'affermazione sul tipo che deve essere soddisfatto dal diagramma prima che possa corrispondere. Quindi, sì, è simile alle guardie, ma non completamente.
Come funziona questo particolare esempio? Tuffati in sources of "base" library per scoprire che:
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
vediamo che IOException
e ArithException
sono diversi tipi di attuazione del typeclass Exception
. Vediamo anche che toException/fromException
è un involucro/meccanismo di togliere l'involucro che permette di convertire i valori di tipo Exception
da/per valori di tipo IOException
, ArithException
, ecc
Quindi, avremmo potuto scrivere:
f = expr `catches` [Handler handleArith,
Handler handleIO]
handleArith :: ArithException -> IO()
handleArith ex = ....
handleIO :: IOException -> IO()
handleIO ex = ....
Supponiamo che si verifichi IOException
. Quando catchesHandler
elabora il primo elemento dell'elenco dei gestori, chiama tryHandler
, che chiama fromException
. Dalla definizione di tryHandler
segue che il tipo di ritorno dello fromException
dovrebbe essere lo stesso argomento di handleArith
. D'altra parte, e
è di tipo Exception, vale a dire - (IOException ...). Così, i tipi di giocare fuori in questo modo (questo non è un Haskell valida, ma spero che si ottiene il mio punto):
fromException :: (IOException ...) -> Maybe ArithException
Dal instance Exception IOException ...
segue immediatamente che il risultato è Nothing
, quindi questo gestore è saltato . Con lo stesso ragionamento si chiamerebbe il seguente gestore, perché fromException
restituirebbe (Just (IOException ...))
.
tipo firme Quindi, che hai usato di handleArith
e handleIO
per specificare quando ognuno di loro sarebbe stato chiamato, e fromException/toException
fatto in modo che sia successo in questo modo.
Se si desidera, è anche possibile utilizzare i tipi di vincolo handleIO
e handleArith
all'interno della definizione di f
, utilizzando variabili di tipo scoped. Probabilmente, questo potrebbe darti una migliore leggibilità.
Finalizzazione, tipo scopato Le variabili qui non sono i principali. Sono solo usati per comodità. Macchine principali per giocare questo tipo di trucchi è fromException/toException
e amici. Le variabili di tipo scopate consentono solo di avere una sintassi che assomigli più da vicino ai modelli di guardia.
Come sono coinvolte le variabili di tipo scoped? Non vedo questo meccanismo al lavoro nella fonte delle catture. – me2
Aggiornato per spiegare dagli escrementi OutExcement/ToException – ADEpt