haskell - monadas - Combinando las mónadas estatales y estatales
monadas filosofía (3)
Aún más en general, lo que estás tratando de hacer es aplicar una transformación a una capa interna de una pila de transformadores. Para dos mónadas arbitrarias, la firma de tipo podría tener este aspecto:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
Básicamente un fmap
nivel fmap
. De hecho, probablemente también tendría más sentido combinarlo con un mapa sobre el parámetro final:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
Claramente, esto no va a ser posible en todos los casos, aunque cuando la mónada "fuente" es Identity
es probable que sea más fácil, pero puedo imaginar definir otra clase de tipos para los lugares en los que funciona. No creo que haya nada como esto en las típicas bibliotecas de transformadores de mónadas; sin embargo, algunos navegando en hackage muestran algo muy similar en el paquete Monatron
:
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 para tmap''
, los tipos de FunctorD
son básicamente implementaciones ad-hoc de fmap
lugar de usar instancias de Functor
directamente.
Además, para dos constructores de tipo similar a Functor F y G, una función con un tipo como (forall a. F a -> G a)
describe una transformación natural de F a G. Es posible que haya otra implementación del mapa de transformador que Quiero un lugar en el paquete de category-extras
, pero no estoy seguro de cuál sería la versión teórica de la categoría de un transformador de mónada, así que no sé cómo podría llamarse.
Dado que tmap
solo requiere una instancia de Functor
(que debe tener cualquier Monad
) y una transformación natural, y cualquier Monad
tiene una transformación natural de la mónada de Identity
proporcionada por return
, la función que desea puede escribirse genéricamente para cualquier instancia de FMonadT
como tmap (return . runIdentity)
asumiendo que la mónada "básica" se define como un sinónimo para el transformador aplicado a la Identity
, en cualquier caso, como suele ser el caso con las bibliotecas de transformadores.
Volviendo a su ejemplo específico, tenga en cuenta que Monatron sí tiene una instancia de FMonadT
para StateT
.
Digamos que tengo una función
f :: State [Int] Int
y una función:
g :: StateT [Int] IO Int
Quiero usar f
in g
y pasar el 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, ¿existe una función de biblioteca para ello?
Lo que está solicitando es un mapeo (conocido como morfismo de mónada) desde una mónada StateT m
hasta StateT n
. mmorph
biblioteca mmorph
, que proporciona un conjunto muy agradable de herramientas para trabajar con morfismos de mónada.
Para realizar la transformación State -> StateT m
que está buscando, comenzaremos por definir un morfismo para generalizar la mónada de Identity
incorporada en el State
,
generalize :: Monad m => Identity a -> m a
generalize = return . runIdentity
A continuación, querremos levantar este morfismo para actuar sobre la mónada interior de su StateT
. Es decir, queremos una función que, dada una asignación de una mónada a otra (por ejemplo, nuestro morfismo generalize
), nos dé una función que actúa en la mónada base de un transformador de mónada, por ejemplo, t Identity a -> tma
. Encontrará que esto se asemeja a la función de mmorph
de la clase MFunctor
,
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b
Poniendo las piezas juntas,
myAction :: State s Int
myAction = return 2
myAction'' :: Monad m => StateT s m Int
myAction'' = hoist generalize myAction
Tal función no es definible para todos los transformadores de mónada. La mónada Cont r
, por ejemplo, no puede elevarse 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
).