2015-07-04 6 views
9

Ora che lo Control.Monad.Error è deprecato e Control.Monad.Except regna sovrana, molte fonti online non hanno recuperato e mostrano ancora esempi di come utilizzare Error.Adattamento dell'errore ad eccezione di

Quindi, come potrei fare per trasformare

instance Error MyError where 
    noMsg = ... 
    strMsg = ... 

in qualcosa usando Except. Basta sostituire Error con Except non ha funzionato come Except si aspetta che i parametri di tipo aggiuntivi

Capisco che questi metodi esatti non esistono in Except, quindi qual è l'alternativa?

risposta

9

risposta breve è: Sostituire Error dal nulla, sostituire ErrorT da ExceptT, e le cose dovrebbero continuare a funzionare finché non si utilizza Error s metodi, fail (che ora ha una diversa definizione), o, in mancanza pattern corrisponde alla notazione do.

La differenza essenziale tra il vecchio sistema Control.Monad.Error e il nuovo sistema Control.Monad.Except è che il nuovo sistema impone alcuna restrizione classe del tipo di errore/eccezione.

È stato rilevato che la possibilità di utilizzare qualsiasi tipo di errore/eccezione, in modo polimorfico, era più utile della capacità un po 'hacky di personalizzare la conversione dei messaggi di errore stringa.

Quindi la classe Error è semplicemente scomparsa.

Come effetto collaterale, fail per ExceptT ora viene rimosso dalla monade sottostante. Ciò cambia anche l'effetto dei modelli non riusciti nella notazione do.

La vecchia definizione era:

fail msg = ErrorT $ return (Left (strMsg msg)) 

che credo sia equivalente a

fail msg = throwError (strMsg msg) 

Se hai ancora bisogno di questo comportamento, è possibile utilizzare invece

throwError yourIntendedErrorValue 

(throwE opere invece se stai utilizzando transformers (ovvero Control.Monad.Trans.Except) piuttosto che mtl.)

Il vecchio modello do mancata corrispondenza si applicherebbe a cose come

do 
    Just x <- myErrorTAction 
    ... 

quando l'azione in realtà restituisce Nothing. Questo è più imbarazzante, ma potresti ad es.sostituirlo con un case partita esplicito (essenzialmente Dezuccheraggio esso):

do 
    y <- myErrorTAction 
    case y of 
     Nothing -> throwE ... 
     Just x -> do 
      ... 

@DanielWagner suggerisce la seguente per evitare il rientro in più:

do 
    x <- myErrorTAction >>= maybe (throwError ...) return 
    ... 

La rimozione di Error elimina anche la necessità di una contraddizione nella denominazione quello Control.Monad.Error aveva: La maggior parte dei trasformatori segue la regola che SomethingT è il nome del trasformatore e Something è un alias di tipo per SomethingT ... Identity. Il vecchio ErrorT si è rotto perché la classe Error è stata utilizzata per qualcosa di completamente diverso.

Nel nuovo sistema, Except e = ExceptT e Identity, come per altri trasformatori.

+0

hai detto che 'fail' funziona in modo diverso ora, potresti fornire un esempio di come fosse e di come sarebbe stato necessario scrivere codice equivalente? –

+0

@ElectricCoffee Ho espanso quel bit. –

+1

@ ØrjanJohansen Un altro pattern che ho usato occasionalmente: 'do {y <- myErrorTAction >> = forse (throwError ...) return; ...} '. Evita di dover aggiungere un livello di indentazione e può essere adattato ad altre corrispondenze di pattern; per esempio. 'do {y_ <- myErrorTAction; y <- caso y_ di {Nothing -> throwError ...; Solo v -> return v}; ...} 'che aggiunge uno strato di indentazione ma solo temporaneamente (cioè non richiederebbe un rientro annidato se si desidera eseguire due corrispondenze di pattern). –