English 中文(简体)
Can somebody walk me through this Haskell function (State monad related)?
原标题:
tick :: State Int Int
tick = get >>= 
 ->
       put (n+1) >>= y ->
       return n

I m confused as to how put (n+1) has any effect on the end result of this function at all. It seems like this function should return the initial state unchanged. I m trying to run through this in my mind, but I keep running out of room to hold things in place. :

If someone could walk me through the evaluation of this function, it would be really helpful.

最佳回答

...How is puts updating the state in the first place? It seems to just be sitting there doing nothing...

Ah, now I understand your question. You re wondering how put (and get) work, right?

Maybe an example in JavaScript will help (a language with actual mutable state):

var s; // mutable state
function get() { return s; }
function put(x) { s = x; }

function tick() {
    var n = get();
    put(n + 1);
    return n;
}

I hope this illustrates that, while n doesn t change, the internal state still will get updated. If you execute tick() twice, the state will be incremented twice.

To get back to Haskell, here s the full definition of (the relevant parts) of the 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)

Now try to expand your tick example even further by manually inlining >>=, return, get and put. Hopefully it will get more clear how State works.

问题回答

You re completely right. The "result" of tick "function" is the initial value of the state.

Now of course, tick isn t the real "function", but a computation that can read and write state before producing a result.
In this case, the state is updated, but you re still returning the original value of the 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

In this case, since you re never inspecting the state again inside tick, you re not seeing the changed state. However, if some other computation happens after tick, it can see the updated state.

For example, doing tick twice (the second one will read the updated state):

-- 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

it might help to write it using do notation

tick :: State Int Int
tick = do
    n <- get    -- get the state
    put (n+1)   -- save an incremented state
    return n    -- return the original state

while the put (n+1) does not impact the result of the computation, it does alter the state that is held within the state monad.





相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?

热门标签