Объединить состояние с действиями ввода-вывода

Предположим, у меня есть государственная монада, такая как:

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)

с такими функциями, как

getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)

updState :: (ST -> ST) -> Op ()
updState g = Op (\st -> (g st, ()))

и так далее. Я хочу объединить различные операции в этой монаде с действиями ввода-вывода. Поэтому я мог бы написать цикл оценки, в котором выполнялись операции в этой монаде и выполнялось действие ввода-вывода с результатом, или, я думаю, я мог бы сделать что-то вроде следующего:

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

Функции печати будут иметь тип Op (), а другие функции будут иметь тип Op a, например, я мог бы читать символ из терминала, используя функцию типа IO Char. Однако я не уверен, как будет выглядеть такая функция, поскольку, например, следующее недопустимо.

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

поскольку getLine имеет тип IO Char, но это выражение будет иметь тип Op Char. В общих чертах, как бы я это сделал?

Ответы на вопрос(2)

Ваш ответ на вопрос