2010-02-16 13 views
6

Se guardate l'esempio per catches:È possibile definire un meccanismo di protezione personalizzato in Haskell?

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

Sembra catches ha definito un meccanismo personalizzato per abbinare sui modelli (i due tipi di eccezione). Sto sbagliando, o può essere generalizzato per consentire a uno di definire una funzione che può assumere funzioni lambda che corrispondono ad un determinato pattern?

Modifica: FYI di seguito è la fonte GHC per le catture. Se qualcuno può far luce su come funziona, sarebbe fantastico.

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 

risposta

5

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.

+0

Come sono coinvolte le variabili di tipo scoped? Non vedo questo meccanismo al lavoro nella fonte delle catture. – me2

+0

Aggiornato per spiegare dagli escrementi OutExcement/ToException – ADEpt

1
case() of 
()| foo expr1 -> handleFooCase 
    | bar expr2 -> handleBarCase 
    | otherwise -> blah 
Problemi correlati