假设我有一个单子状态如:结合状态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)
与功能,如
getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)
updState :: (ST -> ST) -> Op()
updState g = Op (\st -> (g st,()))
等等。我想将这个monad中的各种操作与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。概述,我将如何做到这一点?
我意识到(现在)所提出的解决方案是标准的,但这是一个非常有趣(优雅)的解决方案。使用monad变换器重写我的代码非常有用,因为它提供了一个具体示例。谢谢! – danportin 2010-09-04 22:15:55
Martijn的实用解决方案是一个很好的教育补充。 – 2015-08-24 08:33:31