Greg Heartsfield home

A Simple Game with StateT

I think I first “got” monad transformers after reading the wonderful article Grok Haskell Monad Transformers by Dan Piponi. But it wasn’t without some frustration, and I think that was due to the use of arbitrary functions (test1, test2, go1, go2…). I found it hard to wrap my mind around the bigger issue of the transformer mechanics when I didn’t have a firm grasp on what the purpose of these individual functions were.

So, I wrote the ubiquitous “Guess a number” program, that many probably first wrote in BASIC, using Haskell and a State Transformer instead.

guess_a_number.hs, or improved version with error handling (submitted by

module Main where
import System.Random
import Control.Monad.State

main = do answer <- getStdRandom (randomR (1,100)) -- think of a number
          putStrLn "I'm thinking of a number between 1 and 100, can you guess it?"
          guesses <- execStateT (guessingSession answer) 0 
          putStrLn $ "Success in " ++ (show guesses) ++ " tries."

guessSession :: Int -> StateT Int IO ()
guessSession answer = 
    do gs <- lift getLine    -- get guess from user
       let g = read gs       -- convert to number
       modify (+1)           -- increment number of guesses
       case compare g answer of
              LT -> do lift $ putStrLn "Too low"
                       guessSession answer
              GT -> do lift $ putStrLn "Too high"
                       guessSession answer
              EQ -> lift $ putStrLn "Got it!"

It illustrates a few things rather nicely I think, especially given it is only 20 lines long.

Much thanks to Don and Cale from #haskell for showing me how to write a proper case statement!

Validate XHTML Validate CSS