scsibug.com

November 28, 2006

A Simple Game with StateT

Filed under: Haskell, Programming, Technology — greg @ 11:51 pm

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 tphyahoo@gmail.com).

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.

  • Moving a function argument into the State monad (It is easy to see how guessSession might take two arguments, the answer, and number of guesses made).
  • Incorporating state and IO into the same function, by use of StateT.
  • recursive StateT/IO “Just Works”
  • Highly imperative, state changing, I/O code can be written in Haskell in much the same way as other languages. That is to say, it’s not the pain you might expect given Haskell’s goal of purity.
  • Much thanks to Don and Cale from #haskell for showing me how to write a proper case statement!

2 Comments »

  1. […] Some guy who, judging by what appears to be a pro-illegal immigration rally photo as the header of his blog, apparently doesn’t believe America has the right to defend its borders or its sovereignty, has an interesting, more realistic example of using monad transformers which is, as he points out, more concrete. […]

    Pingback by A Haskell study plan « Metacircular thoughts — March 5, 2007 @ 10:05 pm

  2. Very nice example.

    As an exercise, I modified this so that it asks you to keep trying to enter an integer if you enter something that doesn’t parse as a number. In order to create a handle-able error, I wrote a monadic version of read that uses fail rather than error when there’s no parse.

    Guess a number, improved

    Comment by tphyahoo — November 17, 2007 @ 6:03 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress