No creo que esa definición para SbT
sea lo que quiere. Eso define functor composición, y suponiendo que el parámetro m
es un Functor
o Applicative
, esto debería conservar esas propiedades. Pero una composición como esa no crea, en general, una nueva mónada entre otras dos. Consulte this question para obtener más información sobre ese tema.
Entonces, ¿cómo hacer usted crea el transformador de mónada que desea, entonces? Mientras que las mónadas no se componen directamente, se pueden componer los transformadores de mónada. Por lo tanto, para construir un nuevo transformador a partir de los existentes, básicamente solo desea dar un nombre a esa composición. Esto difiere del newtype
que tiene porque aplica el m
directamente, en lugar de pasarlo a la pila del transformador.
Una cosa a tener en cuenta acerca de la definición de los transformadores de mónada es que necesariamente funcionan "hacia atrás" de ciertas maneras: cuando aplica un transformador compuesto a una mónada, el transformador "interno" obtiene la primera grieta en él, y la mónada transformada que produce es con la que trabaja el siguiente transformador, & c. Tenga en cuenta que esto no es diferente del orden que obtiene al aplicar una función compuesta a un argumento, p. (f . g . h) x
da el argumento primero a h
, aunque f
es la "primera" función en la composición.
bien, así que su transformador compuesto tiene que tomar la mónada que se aplica a y pasarlo al transformador más interna, que es, uhm .... Vaya, resulta que es SB
ya aplicado a una mónada. No es de extrañar que esto no funcionara. Tendremos que eliminar eso, primero. ¿Dónde está? No State
--we podría eliminar eso, pero no queremos, porque es parte de lo que desea. Hmm, pero espera - ¿qué es State
definido como, otra vez? Oh, sí:
type State s = StateT s Identity
Aha, ahí vamos. Vamos a sacar ese Identity
de allí.Vamos a partir de su definición actual:
type SB i a = ReaderT (AlgRO i) (State (AlgState i)) a
Para la forma equivalente:
type SB i a = ReaderT (AlgRO i) (StateT (AlgState i) Identity) a
Luego lanzar la vago perezoso:
type SB' i m a = ReaderT (AlgRO i) (StateT (AlgState i) m) a
type SB i a = SB' i Identity a
Pero ahora SB'
parece sospechosamente a un transformador mónada definición, y con buena razón, porque lo es. Así que recrear la envoltura newtype
, y tirar algunos casos por ahí:
newtype SbT i m a = SbT { getSB :: ReaderT (AlgRO i) (StateT (AlgState i) m) a }
instance (Functor m) => Functor (SbT i m) where
fmap f (SbT sb) = SbT (fmap f sb)
instance (Monad m) => Monad (SbT i m) where
return x = SbT (return x)
SbT m >>= k = SbT (m >>= (getSB . k))
instance MonadTrans (SbT i) where
lift = SbT . lift . lift
runSbT :: SbT i m a -> AlgRO i -> AlgState i -> m (a, AlgState t)
runSbT (SbT m) e s = runStateT (runReaderT m e) s
Un par de cosas a tomar nota de: La función runSbT
aquí no es el descriptor de acceso de campo, sino más bien una función compuesta "correr" para cada transformador en la pila que conocemos. Del mismo modo, la función lift
tiene que levantar una vez para los dos transformadores internos, luego agregar la envoltura final newtype
. Ambos hacen que funcione como un solo transformador de mónada, ocultando el hecho de que en realidad es un compuesto.
Si lo desea, también debería ser sencillo escribir instancias para MonadReader
y MonadState
, al levantar las instancias de los transformadores compuestos.
que lo hará. ¡Gracias! – dsign