为什么runState签名只有状态参数?

Ily*_*gin 7 monads state haskell

一个现实生活中的例子:如果我心情愉快('良好的状态'),当经理问我估计时,我会给他一个坚实的答案,但他敢连续 3次这样做,没有一些免费的中间的小吃,我的情绪发生了变化(我变成了"糟糕的状态"),接下来的3次接近,我请他不要用任何胡言乱语打扰我.

这是我平时的日志:

                             [ Mood: Good, Patience: 3 ]  -- 11:00 am, I'm happy
ESTIMATE -> "bla bla 6",     [ Mood: Good, Patience: 2 ]
ESTIMATE -> "bla bla 1",     [ Mood: Good, Patience: 1 ]
Cookies! -> "",              [ Mood: Good, Patience: 3 again! ]
ESTIMATE -> "bla bla 7",     [ Mood: Good, Patience: 2 ]
ESTIMATE -> "bla bla 2",     [ Mood: Good, Patience: 1 ]
ESTIMATE -> "bla bla 9",     [ Mood: BAD , Patience: -2 ] -- Enough!
ESTIMATE -> "Need a break!"  [ Mood: BAD , Patience: -1 ]
ESTIMATE -> "Deploynig!",    [ Mood: BAD , Patience: 0 ]
ESTIMATE -> "Lunch time!",   [ Mood: Good, Patience: 3 ]  -- Ok he needs me..
ESTIMATE -> "bla bla 6",     [ Mood: Good, Patience: 2 ]
...
Run Code Online (Sandbox Code Playgroud)

现在这个我工作的模型似乎适合StateMonad.

newtype State s a = State { runState :: s -> (a, s) } 
Run Code Online (Sandbox Code Playgroud)

但是我该怎么做?签名有一个状态的空间,在我的情况下(Mood,Patience),而不是输入(ESTIMATE或Cookies).这就像我应该在没有听的情况下回答!

所以我的问题是:我如何使用Haskell monad进行有状态计算而且还进行有争议的计算State?

Bak*_*riu 8

有状态计算获得输入,状态并返回输出和新状态.所以类型将是input -> state -> (state, output).

这runState只是已经采用其输入的部分应用的有状态计算.

还要注意,当你编写有状态函数时(即当你使用>>=绑定操作符或do符号时),你就是这样做的:你将输入作为表达式提供,而bind只负责传递状态.

您可以在get不使用其返回值的情况下调用,但随后会丢失.如果你想使用它,你必须使用value <- get然后提供value作为下一个有状态计算的显式输入.绑定仅在通过状态时发挥作用.


实际例子:考虑功能:

doStuff :: Int -> State Int Int
doStuff x = do
    val <- get
    put $ val+x+1
    return 0
Run Code Online (Sandbox Code Playgroud)

该doStuff类型具有完全相同的模式input -> state -> (state, output).但该input部分由x论证代表.一旦你提供了x你得到的东西,state -> (state, output)这正是runState代表什么.

因此,您实际上并不需要有状态操作的参数,因为您可以事先部分应用它们以获得"没有输入的纯状态计算"(这些是可怕的引用).