I'm trying to understand how to use State in a function. I've avoided the topic for several years because State just never seemed very useful, but I figure it's time for me to figure it out:<div><br></div><div>
I have the following function</div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> update :: (a -> (r,a)) -> Int -> [a] -> (r, [a])</span></font></div>
<div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> update s 0 (a:as) = let (r,a') = s a in (r,a':as)</span></font></div>
<div>
<font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> update s i (a:as) = let (r,as') = update s (i-1) as in (r, a:as')</span></font></div>
<div><br></div><div>which updates a particular element of a list. Looking at it, I see two parts of the type signature that look like State types, which leads me to think of this:</div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace">> update' :: State a r -> Int -> State [a] r</font></div>
<div><br></div><div>Which leads to me writing this:</div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> update' s 0 = do</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> (a:as) <- get</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> let (r, a') = runState s a</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> put (a':as)</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> return r</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> update' s i = do</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> (a:as) <- get</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> put as</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> r <- update' s (i-1)</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> as' <- get</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> put (a:as')</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: small;">> return r</span></font></div><div><br></div><div>Now, this just looks awful. The first half, the base condition, is actually "running" a State calculation. And the second half sets the state within the monad twice!</div>
<div><br></div><div>I like the idea of using State because it simplifies the type. When I see (a -> (b,a)) I say "Wait a second, that's a State calculation, isn't it?" and then, hopefully, generalize. But I can't write that calculation nearly as concisely. How do I do this properly?</div>
</div></div></div></div>