我正在编写一个Haskell程序,它涉及模拟一个抽象机器,它具有内部状态,接受输入并提供输出.我知道如何使用状态monad实现这一点,从而产生更清晰,更易于管理的代码.
我的问题是,当我有两个(或更多)有状态对象相互交互时,我不知道如何使用相同的技巧.下面我给出了一个高度简化的问题版本,并勾勒出我到目前为止的内容.
为了这个问题,让我们假设一个机器的内部状态只包含一个整数寄存器,因此它的数据类型是
data Machine = Register Int
deriving (Show)
Run Code Online (Sandbox Code Playgroud)
(实际的机器可能有多个寄存器,程序指针,调用堆栈等等,但现在不要担心.)在上一个问题之后我知道如何使用状态monad实现机器,所以我不必显式传递其内部状态.在这个简化的示例中,导入后实现如下所示Control.Monad.State.Lazy
:
addToState :: Int -> State Machine ()
addToState i = do
(Register x) <- get
put $ Register (x + i)
getValue :: State Machine Int
getValue = do
(Register i) <- get
return i
Run Code Online (Sandbox Code Playgroud)
这让我可以写出类似的东西
program :: State Machine Int
program = do
addToState 6
addToState (-4)
getValue
runProgram = evalState program (Register 0)
Run Code Online (Sandbox Code Playgroud)
这会将6添加到寄存器,然后减去4,然后返回结果.状态monad跟踪机器的内部状态,以便"程序"代码不必明确跟踪它.
在命令式语言的面向对象样式中,这个"程序"代码可能看起来像
def runProgram(machine):
machine.addToState(6)
machine.addToState(-4)
return machine.getValue()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我想模拟两台彼此交互的机器,我可能会写
def …
Run Code Online (Sandbox Code Playgroud)