Combinar estado con acciones IO

Supongamos que tengo una mónada estatal como:

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, ()))

Etcétera. Quiero combinar varias operaciones en esta mónada con acciones de IO. Por lo tanto, podría escribir un ciclo de evaluación en el que se realizaran operaciones en esta mónada y se ejecutara una acción IO con el resultado, o, creo, debería poder hacer algo como lo siguiente:

newtype Op a = Op {runOp :: ST -> IO (ST, a)}

Las funciones de impresión tendrían el tipo Op () y otras funciones tendrían el tipo Op a, por ejemplo, podría leer un carácter desde el terminal utilizando una función del tipo IO Char. Sin embargo, no estoy seguro de cómo se vería tal función, ya que, por ejemplo, lo siguiente no es válido.

runOp (do x <- getLine; setMem 10 ... (read x :: Int) ... ) st

dado que getLine tiene el tipo IO Char, pero esta expresión tendría el tipo Op Char. En resumen, ¿cómo haría esto?

Respuestas a la pregunta(2)

Su respuesta a la pregunta