TL:DR: Is there a way to do example 3 without passing an argument
I'm trying to understand the state monad in haskell (Control.Monad.State). I made an extremely simple function:
Example 1
example :: State Int Int
example = do
e <- get
put (e*5)
return e
This example works in ghci...
runState example 3
(3,15)
I modified it to be able to take arguments....
Example 2
example :: Int -> State Int Int
example n = do
e <- get
put (e*n)
return e
also works in ghci...
runState (example 5) 3
(3,15)
I made it recursive, counting the number of steps it takes for a computation to satisfy some condition
Example 3
example :: Int -> State Int Int
example n = do
e <- get
if (n /= 1)
then do
put (succ e)
example (next n)
else return (succ e)
next :: Int -> Int
next n
| even n = div n 2
| otherwise = 3*n+1
ghci
evalState (example 13) 0
10
My question is, is there a way to do the previous example without explicitly passing a value?
You can store n
in the state along side of e
, for example, something like:
example = do
(e,n) <- get
if n /= 1
then do put (succ e, next n); example
else return e
There is some overhead to using the State monad, so you should compare this with the alternatives.
For instance, a more Haskelly way of approaching this problem is compose list operations to compute the answer, e.g.:
collatz :: Int -> [Int]
collatz n = iterate next n
collatzLength n = length $ takeWhile (/= 1) $ collatz n