有人可以引导我完成这个Haskell函数(State monad相关)吗?

Ray*_*yne 7 monads state haskell

tick :: State Int Int
tick = get >>= \n ->
       put (n+1) >>= \y ->
       return n
Run Code Online (Sandbox Code Playgroud)

put (n+1)对这个功能的最终结果有什么影响感到困惑.似乎这个函数应该返回初始状态不变.我想在脑海中试图解决这个问题,但是我一直没有足够的空间把东西拿到位.:\

如果有人可以引导我完成对此功能的评估,那将非常有帮助.

Tom*_*rst 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;
}
Run Code Online (Sandbox Code Playgroud)

我希望这说明,虽然n不会改变,但内部状态仍会得到更新.如果执行tick()两次,状态将递增两次.

要回到Haskell,这里是Statemonad (相关部分)的完整定义:

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)
Run Code Online (Sandbox Code Playgroud)

现在尝试扩大你的tick例子甚至进一步通过手动内联>>=,return,getput.希望它能更清楚地说明国家的运作方式.


Tom*_*rst 7

你是完全正确的.tick"功能" 的"结果" 是状态的初始值.

当然,tick现在不是真正的"函数",而是在生成结果之前可以读写状态的计算.
在这种情况下,状态会更新,但您仍然返回状态的原始值:

-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于你再也没有在里面检查状态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
Run Code Online (Sandbox Code Playgroud)


bar*_*ley 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
Run Code Online (Sandbox Code Playgroud)

虽然put (n+1)不会影响计算结果,但它确实会改变状态monad中保持的状态.