Nat*_*iel 2 monads haskell state-monad
我是Haskell的初学者,我遇到过我想使用状态monad的情况.(或者至少,我认为我就是我想要使用的.)状态monad有一百万个教程,但所有这些教程似乎都认为我的主要目标是在深层次的概念层面理解它,并且因此,他们在他们说如何用它实际开发软件的部分之前就停止了.所以我正在寻求一个简化的实际例子的帮助.
下面是我当前代码的简单版本.正如您所看到的,我正在通过我的函数来处理状态,我的问题就是如何使用do
符号重新编写代码,这样我就不必这样做了.
data Machine = Register Int
addToState :: Machine -> Int -> Machine
addToState (Register s) a = Register $ s+a
subtractFromState :: Machine -> Int -> Machine
subtractFromState (Register s) a = Register (s-a)
getValue :: Machine -> Int
getValue (Register s) = s
initialState = Register 0
runProgram = getValue (subtractFromState (addToState initialState 6) 4)
Run Code Online (Sandbox Code Playgroud)
代码模拟一个简单的抽象机器,它具有一个寄存器,以及添加到寄存器的指令,从中减去并获取其值.最后的"程序"将寄存器初始化为0,向其中加6,减去4并返回结果,当然为2.
我理解状态monad的目的(或者至少认为我这样做),并且我希望它能让我重新编写这个,这样我最终会得到像
runProgram :: ???????
runProgram = do
put 0
addToState 6
subtractFromState 4
value <- getValue
return value
Run Code Online (Sandbox Code Playgroud)
然而,尽管我读过所有教程,但我仍然不太清楚如何将代码转换为这种形式.
当然,我的实际机器的状态要复杂得多,而且我也传递它的输出(将传递给另一台机器)和其他各种东西,所以我非常希望简化它.知道如何为这个简化的例子做这件事将是一个非常大的帮助.
更新:在李的好回答之后,我现在知道如何做到这一点,但是当我有多个交互式机器时,我仍然坚持如何以相同的优雅形式编写代码.我在一个新问题中询问过这个问题.
首先,您需要将现有函数转换为返回State Machine a
值:
import Control.Monad.State.Lazy
data Machine = Register Int
addToState :: Int -> State Machine ()
addToState i = do
(Register x) <- get
put $ Register (x + i)
subtractFromState :: Int -> State Machine ()
subtractFromState i = do
(Register x) <- get
put $ Register (x - i)
getValue :: State Machine Int
getValue = do
(Register i) <- get
pure i
Run Code Online (Sandbox Code Playgroud)
然后你可以将它们组合成一个有状态的计算:
program :: State Machine Int
program = do
addToState 6
subtractFromState 4
getValue
Run Code Online (Sandbox Code Playgroud)
最后你需要运行这个计算evalState
来获得最终结果并丢弃状态:
runProgram :: Int
runProgram = evalState program (Register 0)
Run Code Online (Sandbox Code Playgroud)