Предположим, у меня есть монада состояний, такая как:
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. В общих чертах, как бы я это сделал?