2012-03-14 27 views
7

tengo una mónada para un cálculo que pueden fallar y hace algún registro:Actualización mónada exterior sólo en el transformador mónada

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

Tengo una función que no dejará pero tiene algunos tala:

f2 :: Writer [String] b 

¿Cuál es la mejor manera de actualizar la mónada de escritor en f1 utilizando el registro de f2 y capturar el resultado del cálculo de f2? En el momento que estoy haciendo esto:

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

estoy usando ascensor para actualizar la mónada interior con un cálculo diferente, por lo tanto cambiar todo el escritor y mónadas o bien no va a resolver el problema.

+0

Gracias danr y rampion por sus respuestas. Elegí usar el método de ajuste. Aunque podría cambiar el tipo de f2, esa función aparece en otros contextos, por lo tanto, me gustaría escribir su tipo sin referencia a las necesidades de una función de llamada en particular. – mskel

Respuesta

4

Si ha definido f2, el enfoque más fácil posible puede ser refactorizar f2 por lo que se define así:

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

cual no debería ser demasiado difícil, ya que Writer w b se define como WriterT w Identity b, y el Identity mónada doesn Te doy algo.

Entonces podrá encadenarlos simplemente haciendo f1 >> f2.

Si no puede volver a definir f2, siempre se puede definir su propio con la firma apropiada:

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

Y si usted tiene un montón de f2 para envolver, siempre se puede definir una función para envolver para usted

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

por lo que puede hacer f1 >> wrap f2a >> wrap f2b >> wrap f2c ...

4

Como seguimiento a la respuesta de rampion, en su lugar puede ref el actor f2 en cualquier MonadWriter:

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

En caso de que no sea posible cambiar su definición se puede lo envuelven de manera similar como rampion hace:

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

El argumento [String] a MonadWriter requiere este pragma GHC:

{-# LANGUAGE FlexibleContexts #-} 

Como siempre, pragmas ar Ponlo en la parte superior del módulo.

En los comentarios, rampion dio una versión de envolver una función en este contexto:

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

y el envoltorio se convierte en 'wrap :: MonadWriter w m => Writer w b -> m b; wrap = undecurry (<<). (devolver *** decir). runWriter donde (<<) = flip (>>) ' – rampion

+0

@rampion: ¡Agradable!Puedo apreciar el estilo sin puntos;) – danr

+0

Bueno, permítanme unirme a la sociedad de admiración mutua, y decir que puedo apreciar la generalización de la clase de tipos MonadWriter :) – rampion

Cuestiones relacionadas