The State monad is useful for modeling computations in Haskell that maintain state, the bread and butter of programming in an imperative language. Haskell tutorials for beginners teach us how to pass on the old value of the state with each call of the function, and then extract the new state from the result. Commonly referred to as "threading the state through the computation", this strategy works, but tedius .. and Haskellers will consider this .. boilerplate.
The State monad raises the level of abstraction and decouples the state management from the computation itself. I am not going to write yet another tutorial on monads. Instead I would like to share the example problem which made me understand the State monad quite beautifully.
It is fizzbuzz !! Fizzbuzz has been solved in a multitude of languages of various paradigms. The basic problem that fizzbuzz solves is simple enough to be moulded into demonstrating various idioms of a programming language. Not all of them are efficient or elegant enough, but serves well articulating the idiom in hand - you don't have to stretch yourselves to comprehend the problem that you are trying to solve. You can focus on the solution itself right from the word go. Even Haskell has quite a few solutions to the fizzbuzz problem, but I could not find one that makes use of the State monad. The solution below generates the whole fizzbuzz sequence as a side-effect using monads. This is not the most elegant of solutions for fizzbuzz, does not work for infinite sequences, but I found it quite simple and useful in understanding the State monad in Haskell ..
Without further ado ..
-- the entire fizzbuzz list is prepared as a side-effect
-- collect prepares the list as the State
-- mapM strips the values part
run_fizzbuzz :: [Integer] -> [[Char]]
run_fizzbuzz list =
state where (_, state) = runState (do mapM_ collect list) 
collect :: Integer -> State [[Char]] ()
-- gets the old state and cons s the new
collect n = do
f <- get
put ((fizzbuzz n):f)
fizzbuzz :: Integer -> [Char]
| n `rem` 3 == 0 && n `rem` 5 == 0 = "fizzbuzz"
| n `rem` 3 == 0 = "fizz"
| n `rem` 5 == 0 = "buzz"
| otherwise = show n
main :: IO ()
main = do putStr $ show $ reverse $ run_fizzbuzz [1..100]