1

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?

Obrazi
  • 77
  • 7

1 Answers1

3

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
ErikR
  • 51,541
  • 9
  • 73
  • 124
  • That gives me 'Cannot construct the infinite type' error. I've already used a list solution that takes almost 10 seconds here: https://bpaste.net/show/f306ad518779 I'm trying to get the haskell code to use a similar algorithm to the c++11 code that runs in under a second here: https://bpaste.net/show/b8c67bd4830f Without having to pass around a map, starting number, and count Also I'd like to know how to use the state monad in general. Thanks for the answer I'm trying to get it to work and see where you're going with it. – Obrazi Nov 09 '14 at 00:42
  • Here is a complete working example to help you figure out the type error: http://lpaste.net/113963 – ErikR Nov 09 '14 at 00:43
  • Your question about how to write a Haskell routine that performs as well as the C++ code is worthy of a new SO question. – ErikR Nov 09 '14 at 00:48
  • Well this question was 99% about using the state monad, I was just using the collatz sequence as something I forgot the word of... (to use something really stupid as an explanation and working example, instead of a real world example that would just complicate things more). I'm just beginning to learn about monads and there don't seem to be many of these kinds of over simplified examples around... a lot of them have to do with random numbers and parsers. So thank you very much for the answer it is working now. I just forgot to get rid of the parameter when typing it in. – Obrazi Nov 09 '14 at 00:53