假设我有一个状态单子,如下所示:
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, ()))
等等。我想要将不同的操作与IO动作结合在此单子类型中。因此,我可以编写一个评估循环,其中执行此单子类型中的操作并执行一个IO动作以获得结果,或者,我认为,我应该能够执行以下操作:
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。简单说,我该怎么做?