Tipo de error al intentar implementar la función (>> =) con el fin de crear un transformador mónada personalizada
-
27-09-2019 - |
Pregunta
Estoy intentando crear un transformador mónada para un proyecto futuro, pero por desgracia, mi implementación de la mónada de typeclasse (>> =) función no funciona.
En primer lugar, aquí es la implementación de la mónada subyacente:
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
A continuación, la aplicación de la Mónada typeclasse se realiza automáticamente por GHC (utilizando el lenguaje de Pragma GeneralizedNewtypeDeriving
).
La mónada transformador se define como así:
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
El problema proviene de la forma en que la función instanciate (>> =) de la typeclasse Mónada:
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
A mi modo de ver, las primeras carreras >>=
en la mónada m
subyacente. Por lo tanto, runRuntimeT x >>=
devuelve un valor de tipo Runtime a
(¿verdad?). A continuación, el código siguiente, id >>=
, debería devolver un valor de tipo a
. Este valor es la transmite a la función f de tipo f :: (Monad m) => a -> RuntimeT m b
.
Y aquí viene el problema tipo: Tipo de la función f
no coincide con el tipo requerido por la función (>> =). Jow puedo hacer que esta coherente? Puedo ver por qué esto no funciona, pero no puedo lograr convertirlo en algo functionnal.
Edit: El mensaje de error:
Core.hs:34:4:
Occurs check: cannot construct the infinite type: m = RuntimeT m
When generalising the type(s) for `>>='
In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.
Gracias por su ayuda, y no dude en corregir cualquier defecto en mi mensaje,
Charlie P.
Solución
Para una continuación de lo que dijo Reid Barton sobre StateT
- aquí es cómo definiría RuntimeT
usando StateT
. La mónada Runtime
puede entonces ser trivialmente define utilizando la mónada identidad.
newtype RuntimeT m a = R {
unR :: StateT EInfo m a
}
type Runtime = RuntimeT Identity
instance Monad m => Monad (RuntimeT m) where
return = R . return
(R m) >>= f = R (m >>= unR . f)
Otros consejos
La mónada StateT s m
habitual envía a a
s -> m (a, s)
pero están trabajando con m (s -> (a, s))
lugar. No creo que este último forma una mónada para s
general. ¿Seguro que no sólo quiere utilizar StateT
?
He aquí por qué no creo a
? m (s -> (a, s))
es una mónada: Para >>=
escritura necesito una función que toma argumentos de tipos
m (s -> (a, s))
a -> m (s -> (b, s))
y devuelve un valor de tipo
m (s -> (b, s))
Los "efectos" (es decir fmap (const ())
) del resultado debe ser las del primer argumento, ya que no tenemos manera de obtener una a
para pasar al segundo argumento. Desde m
sólo aparece en la parte exterior del tipo de resultado, entonces no podemos usar el segundo argumento para nada en absoluto, no habrá manera de deshacerse de la m
introduce.