Reputation: 1101
Could somone please tell me why does this piece of code which uses the State monad never end?
fib' :: State [Int] ()
fib' = do l <- get
let l2 = sum (last2 l)
put (l ++ [l2])
return ()
fib'
take 10 $ execState fib' [0, 1]
When I execute it in the ghci REPL, the function executes without stopping.
Upvotes: 2
Views: 276
Reputation: 6563
return
does not work like it does in imperative languaues. It is defined differently for each monad, for the state monad, it is defined as:
return x = State $ \s -> (x,s)
So it doesn't actually break out of the fib'
function, but instead binds a new State monad to the rest of the computation.
EDIT:
While my original answer is true, it does not answer the OP's question. In the OP's code, return
acts as a no-op. For the reason why the OP's code never terminates, see other answers. I am still leaving my answer here because I feel it is still something important to point out, given that return
did show up unnecessarily in the OP's code sample
Upvotes: 4
Reputation: 36339
What you are doing here is more or less equivalent to the following:
rfib (last:last':rest) = let new = last + last' in rfib (new:last:last':rest)
which attempts to create the numbers in reverse order "lazily". (The order doesn't really matter, I just did it in reverse to get rid of the distracting (++) and last2).
But the point is, you never compute a list, as the type checker will tell you. For example, the follwoing are all well typed:
res1 = (take 10 . rfib) [1,0] :: [Int]
res2 = (take 10 . snd . rfib) [1,0] :: [Int]
res3 = (take 10 . snd . snd . rfib) [1,0] :: [Int]
res4 = "foo" == rfib [1,0]
Sometimes it is a good idea to not write annotations, you know. Then you would see that something like this was inferred:
rfib :: Num a => [a] -> b
which corresponds closely to the principal type of your foo':
fib' :: Num a => State [a] b
And this type should you make think a bit. It the case of rfib
it tells that out of nowhere you create a value of any type you want, here called b
.
And this is synonymous for "there is no such value". Like in head []
or unJust Nothing
or error "Bottom"
, any attempt to nevertheless compute that value must diverge.
Matters are different when the fresh type variable that appears in the result is "protected" by a type constructor. Then what happens will depend on the type, whose constructor is applied. As it stands, it works with Writer, but not with State. Still, such an unexpected type should make one think the case over.
Upvotes: 1
Reputation: 54078
At @Joachim Breitner's suggestion, a possible solution using the lazy Writer monad would be:
import Control.Monad.Writer
fib' :: Writer [Int] ()
fib' = tell [1, 1] >> go 1 1
where
go :: Int -> Int -> Writer [Int] ()
go f1 f2 = do
let f3 = f1 + f2
tell [f3]
go f2 f3
main = print $ take 10 $ execWriter fib'
Upvotes: 1
Reputation: 13677
return ()
line is redundant and can be removed(++)
is almost always a bad idea as it's O(N) in the size of its first argument.Upvotes: 4
Reputation: 25782
The result of execState
is the value of the state at the end of the computation. But your computation never ends: fib'
calls fib'
. While in your case it would be possible to prove that the first 10 elements of the state eventually do not change, the compiler is not able to predict that (nor should it).
You might want to check out the Writer Monad, where you can process the written data lazily.
Upvotes: 8