preestablecida monadas monada leibniz las filosofía filosofia espiritual educatina doctrina armonia haskell monads monad-transformers state-monad

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 ).