2011-12-22 11 views
5

Ho il seguente trasformatore monad per gestire gli errori in Haskell.Monadi Haskell e un errore che non richiede una stringa

instance (Monad m, Error e) => Monad (EitherT e m) where 
    return = EitherT . return . return 
    m >>= k = EitherT $ do 
      a <- runEitherT m 
      case a of 
       Left l -> return (Left l) 
       Right r -> runEitherT (k r) 
    fail = EitherT . return . Left . strMsg 

E funziona abbastanza bene, come posso istanziare Error con una classe personalizzata e avere un mezzo abbastanza flessibili da cui gestire gli errori.

fail è un po 'sciocco, però, perché è il tipo String -> EitherT e m e la restrizione String può essere un modo fastidioso per creare errori. Io alla fine con un sacco di:

instance Error BazError where 
    strMsg "foo" = FooError -- oh look we have no error context 
    strMsg "bar" = BarError -- isn't that nice 

Quello che mi piacerebbe fare è creare una nuova funzione, come fail, che è di tipo a -> e in modo che possa rimuovere la restrizione (Error e). fail è particolarmente utile quando la pila Monade diventa grande, come quando alla fine con

EitherT BazError (StateT [BazWarning] IO) Foo 

C'è un modo per creare una funzione che ha lo stesso comportamento fail con un tipo meno restrittivo? O è implementato fail utilizzando la magia dark haskell profonda?

+3

Probabilmente si dovrebbe semplicemente evitare "fail" interamente, a meno che non si voglia personalizzare il comportamento in caso di mancata corrispondenza del modello "do'-block". – ehird

risposta

7

Beh, fail viene chiamato se si dispone di un fallimento del modello-partita in un blocco do, come se si dispone di Just x <- something e risultato something s' è Nothing. Oltre a ciò, fail è una funzione ordinaria.

Per il problema con strMsg "foo" = FooError ecc., throwError offre un'interfaccia migliore per il tuo caso d'uso?

4

Questo articolo può essere utile: http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/

tuo EitherT è già presente nella libreria standard e chiamò ErrorT. Vedere la documentazione: http://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad-Error.html#t:ErrorT

fail è una curiosità storica ora e può essere considerato un difetto di progettazione, insieme alla mancanza del vincolo Functor a => Monad a. È solo una funzionalità controversa per gestire le corrispondenze con pattern non riusciti nella notazione do.

throwError :: MonadError e m => e -> m a 

è la sostituzione più comune per fail, ma più sono disponibili (vedi l'articolo).

Problemi correlati