tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>= \y ->
return n
我对put (n+1)
如何对这个函数的最终结果产生任何影响感到困惑。似乎这个函数应该返回初始状态不变。我想在脑海中试图解决这个问题,但是我一直没有足够的空间把东西拿到位。 :\
如果有人可以引导我完成对此功能的评估,那将非常有帮助。
答案 0 :(得分:10)
啊,现在我理解你的问题了。你想知道......首先更新状态是什么?它似乎只是坐在那里无所事事......
put
(和get
)是如何工作的,对吧?
也许JavaScript中的一个例子会有所帮助(一种具有实际可变状态的语言):
var s; // mutable state
function get() { return s; }
function put(x) { s = x; }
function tick() {
var n = get();
put(n + 1);
return n;
}
我希望这说明,虽然n
没有改变,但内部状态仍会更新。如果执行tick()
两次,状态将递增两次。
回到Haskell,这里是State
monad(相关部分)的完整定义:
newtype State s a = State { runState :: s -> (a, s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
m >>= k = State $ \s -> let
(a, r) = runState m s
in runState (k a) r
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
现在尝试通过手动内联tick
,>>=
,return
和get
来进一步扩展您的put
示例。希望它能更清楚地说明国家的运作方式。
答案 1 :(得分:7)
你是完全正确的。 tick
“函数”的“结果”是状态的初始值。
当然,tick
当然不是真正的“函数”,而是在生成结果之前可以读写 state 的计算。
在这种情况下,状态会更新,但您仍然会返回状态的原始值:
-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state
在这种情况下,由于您从未在tick
内再次检查状态,因此您没有看到更改后的状态。但是,如果在tick
之后发生了一些其他计算,则可以看到更新后的状态。
例如,执行tick
两次(第二次将读取更新的状态):
-- 4 is the inital state
ghci> runState (tick >> tick) 4
(5, 6)
-- 5 is the result of the tick computation executed twice,
-- 6 is the updated state
答案 2 :(得分:5)
使用do
符号
tick :: State Int Int
tick = do
n <- get -- get the state
put (n+1) -- save an incremented state
return n -- return the original state
虽然put (n+1)
不会影响计算结果,但它会改变状态monad中保持的状态。