Domanda

Se si guarda l'esempio per catches:

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

Sembra che catches ha definito un meccanismo personalizzato per abbinare sui modelli (i due tipi di eccezione). Sbaglio o questo può essere generalizzato per consentire di definire una funzione che può assumere le funzioni lambda che corrispondono a un determinato modello?

Modifica: FYI sotto è la fonte GHC per le catture. Se qualcuno può far luce su come funziona sarebbe bello.

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
È stato utile?

Soluzione

Questo è il tipo con ambito Variabili estensione GHC sul posto di lavoro. Segui il link per saperne di più.

In sostanza, si definisce un'affermazione sul tipo che devono essere soddisfatte dal ticchettio prima che possa eguagliare. Quindi, sì, è simile a guardie, ma non del tutto così.

Come funziona questo particolare esempio? Tuffati in fonti di "base" della biblioteca 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

Si vede che IOException e ArithException sono diversi tipi di attuazione del Exception typeclass. Vediamo anche che toException/fromException è un involucro / meccanismo di togliere l'involucro che permette di convertire i valori di tipo Exception a / da 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 = ....

Si supponga che IOException accade. Quando catchesHandler elabora primo elemento della lista gestori, chiama tryHandler, che chiama fromException. Dalla definizione di tryHandler segue che tipo di ritorno del fromException dovrebbe essere lo stesso come argomento di handleArith. D'altra parte, e è di tipo eccezione, cioè - (IOException ...). Così, i tipi di giocare fuori in questo modo (questa non è una valida Haskell, 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 viene saltato. Con lo stesso ragionamento il seguente gestore sarebbe chiamato, perché fromException sarebbe tornato (Just (IOException ...)).

Quindi, hai utilizzato tipo firme di handleArith e handleIO per specificare quando ciascuno di essi sarebbe stato chiamato, e fromException/toException fatto in modo che è successo in questo modo.

Se si vuole, si potrebbe anche vincolo tipi di handleIO e handleArith all'interno della definizione di f, utilizzando le variabili di tipo di ambito. Probabilmente, questo potrebbe dare una migliore leggibilità.

Tipo finalizzazione, con ambito variabili non sono un primario giocatori qui. Essi sono solo utilizzati per convenienza. macchine principali per la riproduzione di questo tipo di trucchi è fromException/toException e gli amici. Variabili di tipo di ambito solo permetterà di avere la sintassi che assomigliano più da vicino i modelli di guardia.

Altri suggerimenti

case () of 
  ()| foo expr1 -> handleFooCase
    | bar expr2 -> handleBarCase
    | otherwise -> blah
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top