Search code examples
haskellrecursionmonadsstate-monad

Haskell State monadic function using recursion


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?


Solution

  • 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