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
.
creo que edición de TomMD es incorrecta. Creo que el original 'g :: StateT [Int] IO Int' debe mantenerse. – glguy
Me han gustado los otros cambios, he arreglado el paréntesis ... – HaskellElephant
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