2010-11-09 13 views
15

Digamos que tengo una funciónStatet y estatales

f :: State [Int] Int 

y una función:

g :: StateT [Int] IO Int 

quiero usar en fg y pasar al estado entre ellos. ¿Hay una función de biblioteca para
StateT (return . runState f)? O, en general, dado un transformador de mónada con una mónada correspondiente, ¿hay una función de biblioteca para ello?

+0

creo que edición de TomMD es incorrecta. Creo que el original 'g :: StateT [Int] IO Int' debe mantenerse. – glguy

+0

Me han gustado los otros cambios, he arreglado el paréntesis ... – HaskellElephant

+1

Esta pregunta parece ser lo que estoy buscando, pero las respuestas son mucho más complicadas que http://stackoverflow.com/questions/17325485/combining-statet- io-with-state, que hizo el trabajo por mí. – crockeea

Respuesta

5

En un aspecto aún más general, lo que intenta hacer es aplicar una transformación a una capa interna de una pila de transformadores. Durante dos mónadas arbitrarias, el tipo de firma podría ser algo como esto:

fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a 

Básicamente un nivel más alto fmap. De hecho, probablemente tendría aún más sentido a combinarlo con un mapa sobre el parámetro final, así:

fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b 

evidente que esto no va a ser posible en todos los casos, sin embargo, cuando la "fuente" mónada es Identity es probable que sea más fácil, pero me puedo imaginar definiendo otra clase de tipo para los lugares donde funciona. No creo que haya algo como esto en las típicas bibliotecas de transformadores de mónada; Sin embargo, algo de navegación en hackage se vuelve algo muy similar in the Monatron package:

class MonadT t => FMonadT t where 
    tmap' :: FunctorD m -> FunctorD n -> (a -> b) 
      -> (forall x. m x -> n x) -> t m a -> t n b 

tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b) 
     -> t m a -> t n a 
tmap = tmap' functor functor id 

En la firma de tmap', los FunctorD tipos son básicamente las implementaciones ad-hoc de fmap en lugar de utilizar directamente Functor casos.

Además, para dos constructores de tipos Functor-como F y G, una función con un tipo como (forall a. F a -> G a) describe a natural transformation de F a G. Hay muy posiblemente otra aplicación de la hoja de transformador que desea alguna parte del conjunto category-extras pero No estoy seguro de cuál sería la versión teórica de categoría de un transformador de mónada, así que no sé cómo se podría llamar.

Desde tmap requiere sólo una instancia Functor (que cualquier Monad debe tener) y una transformación natural, y cualquier Monad tiene una transformación natural de la Identity mónada proporcionada por return, la función que desea se puede escribir de forma genérica para cualquier instancia de FMonadT como tmap (return . runIdentity) - asumiendo que la mónada "básica" se define como sinónimo para el transformador aplicado a Identity, en cualquier caso, que generalmente es el caso de las bibliotecas de transformadores.

Volviendo a su ejemplo específico, tenga en cuenta que Monatron sí tiene una instancia de FMonadT para StateT.

+0

No he visto el paquete Monatron. Tendré que mirar más de cerca para juzgarlo. Me gusta su idea de definir una clase de tipo para cuando funciona, ¿alguien puede confirmar o desconfirmar que Monatron hace esto? – HaskellElephant

4

Tal función no se puede definir para todos los transformadores de mónada. La mónada Cont r, por ejemplo, no se puede subir a ContT r IO porque eso requeriría convertir una continuación en la mónada IO (a -> IO r) en una continuación pura (a -> r).

+0

No pensé en eso. Como dijiste, esto no es posible para todos los monadransformadores. Entonces, requeriría un tipo especial de conexión entre el transformador y la mónada correspondiente, entonces ... – HaskellElephant

+0

¿No sería la transformación lo contrario? Dado que la 'r' en un tipo de continuación suele ser polimórfica, puede escribir' (ContT. RunCont) :: Cont (m r) a -> ContT r m a'. –

+0

@camccann Iba a una clase generalizada de transformaciones (Monad m => m a -> (TransformerOf m) m 'a) (abusando de la notación un poco). Si intentas escribir una instancia para (Cont r a -> ContT r m a), te quedarás atrapado en el punto que describí. – Heatsink

4

Lo que estamos pidiendo es un mapeo (conocido como un morfismo mónada) de una mónada StateT m-StateT n. Utilizaré la biblioteca mmorph, que proporciona un conjunto muy bueno de herramientas para trabajar con morfismos de mónada.

Para realizar la transformada State -> StateT m que busca, vamos a empezar por la definición de un morfismo de generalizar la mónada Identity incrustado en State,

generalize :: Monad m => Identity a -> m a 
generalize = return . runIdentity 

A continuación vamos a querer levantar este morfismo para actuar en la mónada interna de su StateT. Es decir, queremos una función que proporcione un mapeo de una mónada a otra (por ejemplo, nuestro morfismo generalize), nos dará una función que actuará sobre la mónada base de un transformador de mónada, p. t Identity a -> t m a. Encontrará esto se asemeja a la función de hoistmmorph 's MFunctor clase,

hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b 

Juntando las piezas,

myAction :: State s Int 
myAction = return 2 

myAction' :: Monad m => StateT s m Int 
myAction' = hoist generalize myAction 
Cuestiones relacionadas