Puede ver cómo se implementa StateT:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
Para combinar con IO
estado que acaba de poner en su lugar de IO
m
y obtener el tipo deseado: s -> IO (a,s)
.
Si tiene errores también, esto se convierte en algo así como s -> IO (Either e (a, s))
o s -> IO (Either e a, s)
dependiendo de si desea que los cálculos fallidos afecten al estado.
Tenga en cuenta que no puede hacer s -> Either e (IO (a, s))
una mónada
sin una máquina de tiempo
.
actualización
resulta que no se puede hacer una mónada incluso con la máquina del tiempo.
para mostrar por qué es imposible, vamos a simplificar nuestra mónada mediante el uso de ()
en lugar de s
primera: data M e a = M { runM :: Either e (IO a) }
Ahora, imaginemos el siguiente programa:
unsafePerformIO :: IO a -> a
unsafePerformIO io = fromLeft $ runM $ do
a <- M $ Right $ io
M $ Left a
Obviamente, esta función es imposible y por lo tanto, la instancia de mónada para M
también es imposible.
Lo que la máquina del tiempo podría darle es la capacidad de tratar IO
exactamente como uno trata State
. Sin embargo, no me di cuenta de que Either e (s -> (a, s))
no es una mónada.
¿Máquina de tiempo? ¿Puedes proporcionar algún contexto? ¿Es una broma "con intención de juego de palabras", o es algún término avanzado de matemática/ciencia de programación? – Tarrasch
No hay juegos de palabras aquí, estoy hablando de una máquina de tiempo real. Una vez que lo tienes, puedes implementar esta mónada. – Rotsor
@Rotsor: se preocupe por explicar * ¿por qué * dijo que se requiere una máquina de tiempo? – ivanm