Supongamos que tengo una mónada estado tales como:Combinar Estado con acciones IO
data Registers = Reg {...}
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op a = Op {runOp :: ST -> (ST, a)}
instance Monad Op where
return a = Op $ \st -> (st, a)
(>>=) stf f = Op $ \st -> let (st1, a1) = runOp stf st
(st2, a2) = runOp (f a1) st1
in (st2, a2)
con funciones como
getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)
updState :: (ST -> ST) -> Op()
updState g = Op (\st -> (g st,()))
y así sucesivamente. Quiero combinar varias operaciones en esta mónada con acciones IO. Así que podría o bien escribir un bucle de evaluación en el que se realizaron las operaciones en esta mónada y se ejecuta una acción IO con el resultado, o, creo, debería ser capaz de hacer algo como lo siguiente:
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
Impresión las funciones tendrían el tipo Op() y otras funciones tendrían el tipo Op a, por ejemplo, podría leer un carácter del terminal usando una función del tipo IO Char. Sin embargo, no estoy seguro de cómo se vería esa función, ya que, por ejemplo, lo siguiente no es válido.
runOp (do x <- getLine; setMem 10 ... (read x :: Int) ...) st
ya que getLine tiene tipo IO Char, pero esta expresión tendría tipo Op Char. En resumen, ¿cómo podría hacer esto?
Me doy cuenta (ahora) de que la solución presentada es estándar, pero esta es una solución muy interesante (y elegante). Su reescritura de mi código usando un transformador de mónada fue muy útil, ya que proporcionó un ejemplo concreto. ¡Gracias! – danportin
Un buen complemento educativo a la solución pragmática de Martijn. –