Obrazi
Obrazi

Reputation: 77

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?

Upvotes: 1

Views: 1102

Answers (1)

ErikR
ErikR

Reputation: 52059

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

Upvotes: 3

Related Questions