Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

haskell - state monad function get?

one question according to the get function of the State Monad:

If I run

runState get 1

I got the result

(1,1)

and this is ok for me because the get function set the result value to the state and in this case the state is 1. Thus, (1,1) is the result. Ok.

But if I run

runState (do{(a,b) <- get; return a}) (False, 0)

I got the result

(False,(False,0))

And this I don't understand.

The get function set the result value to the state and left the state unchanged. So what I would expect is something like this

((False,0),(False,0))

The same with this

runState (do{(a,b) <- get; return b}) (False, 0)

the result is

(0,(False,0))

I don't understand this again as above descripted.

So, it would be very nice if you could explain me this for me strange results. ;)

Thanks in advance

best regards,

jimmy

like image 466
jimmyt Avatar asked Dec 04 '22 15:12

jimmyt


2 Answers

It's because you do something after the get, namely you return one of the components. Ignoring the newtype-wrapping,

return x = \s -> (x,s)

so

do { (a,b) <- get; return a }   ===   get >>= \(a,b) -> return a

expands to

(\s -> (s,s)) >>= \(a,b) -> (\t -> (a,t))

and with the definition of (>>=) that becomes

\s1 -> let (r,s2) = (\s -> (s,s)) s1
       in (\(a,b) -> (\t -> (a,t))) r s2

And when you run that with an initial state of (False,0), it unfolds

let (r,s2) = (\s -> (s,s)) (False,0)
~> let (r,s2) = ((False,0),(False,0))
in (\(a,b) -> (\t -> (a,t))) r s2
~> in (\(a,b) -> (\t -> (a,t))) (False,0) (False,0)
~> in (\t -> (False,t)) (False,0)    -- match (a,b) with (False,0)
~> in (False, (False,0))

The other case with return b is similar.

like image 106
Daniel Fischer Avatar answered Jan 06 '23 21:01

Daniel Fischer


Daniel’s answer is of course correct and complete, so let me try to answer it from a different angle and discuss possible misunderstandings.

You expected ((False,0),(False,0)) to be returned for

runState (do{(a,b) <- get; return a}) (False, 0)

Now to actually get this expected result, you’d have to write, for example,

runState (do{(a,b) <- get; return (a,b)}) (False, 0)

(which is morally equivalent to runState get (False, 0).

Maybe you were confusing get and runState; the latter returns a tuple where one component is the result of the computation and the other the final state. And indeed you’d take that tuple apart to obtain only the (final) state. get however has one return value, which is just the (current) state and nothing more – no untupling required. If you do take the tuple apart and return only a (or b), then this shows up accordingly as the result of the complete stateful computation, just as you have observed.

like image 25
Joachim Breitner Avatar answered Jan 06 '23 21:01

Joachim Breitner