2012-03-14 11 views
7

Ho una monade per un calcolo che può mancare e fa qualche registrazione:Aggiornamento monad esterno solo trasformatore monade

f1 :: WriterT [String] (Either String) a 

Ho una funzione che non mancherà ma fa qualche registrazione:

f2 :: Writer [String] b 

Qual è il modo migliore per aggiornare il monad writer in f1 utilizzando il log da f2 e acquisire l'output del calcolo f2? Al momento sto facendo questo:

f2result <- (\(r,l) -> do {tell l; return r}) (runWriter f2) 

Sto usando ascensore per aggiornare la monade interno con un calcolo diverso, per cui il passaggio intorno allo scrittore e monadi o non risolverà il problema.

+0

Grazie danr e rampion per le vostre risposte. Ho scelto di usare il metodo wrap. Anche se potrei cambiare il tipo di f2, quella funzione appare in altri contesti, quindi mi piacerebbe scrivere il suo tipo senza fare riferimento alle esigenze di una particolare funzione di chiamata. – mskel

risposta

4

Se è stato definito f2, l'approccio più semplice possibile potrebbe essere quella di refactoring f2 quindi è definito così:

f2 :: Monad m => WriterT [String] m b 

che non dovrebbe essere troppo difficile, dal momento che Writer w b è definito come WriterT w Identity b, e il Identity Monade doesn Ti do qualcosa.

Quindi si sarebbe in grado di concatenarli semplicemente facendo f1 >> f2.

Se non è possibile ridefinire f2, si può sempre definire il proprio con la firma appropriata:

f2' :: Monad m => WriterT [String] m b 
f2' = WriterT . return $ runWriter f2 

E se hai un po 'di f2 per avvolgere, si può sempre definire una funzione per avvolgere per voi

wrap :: Monad m => Writer w b -> WriterT w m b 
wrap = WriterT . return . runWriter 

Così si può fare f1 >> wrap f2a >> wrap f2b >> wrap f2c ...

4

Come un follow-up sulla risposta di raperonzolo, si può invece ref attore f2 su qualsiasi MonadWriter:

f2 :: MonadWriter [String] m => m a 

Nel caso in non essere possibile cambiare la sua definizione si può avvolgerlo allo stesso modo come rampion fa:

f2' :: MonadWriter [String] m => m a 
f2' = do let (a,w) = runWriter f2 
     tell w 
     return a 

La [String] argomento di MonadWriter richiede questo pragma GHC:

{-# LANGUAGE FlexibleContexts #-} 

Come sempre, pragmi ar e metti sopra il modulo.

Nei commenti, raperonzolo ha dato una versione di avvolgere una funzione in questa impostazione:

wrap :: MonadWriter w m => Writer w b -> m b 
wrap = uncurry (<<) . (return *** tell) . runWriter 
    where (<<) = flip (>>) 
+1

e il wrapper diventa 'wrap :: MonadWriter w m => Writer w b -> m b; wrap = uncurry (<<). (return *** tell). runWriter where (<<) = flip (>>) ' – rampion

+0

@rampion: Bello!Posso apprezzare lo stile pointfree;) – danr

+0

Bene, permettimi di unirmi alla società di ammirazione reciproca e di poter apprezzare la generalizzazione della classe di caratteri MonadWriter :) – rampion

Problemi correlati