How to keep track of number of guesses in a simple guessing game (Haskell)

Viewed 1606

I've been attempting to learn Haskell independently in the last few weeks. Currently, I'm trying to implement a goofy little guessing game where the computer chooses a random number and the user tries to guess it. If the user is wrong, the program tells the user either that the answer is higher or lower and allows the user to guess until they guess correctly. I've got it working, but I would like to add the ability to keep track of the number of guesses that the user makes every game and report that number to the user once they guess correctly.

Coming from an imperative background, the natural thing to do would be to have a counter that is incremented every time the user makes a guess, but you can't really do that in Haskell (at least it seems like the statelessness and immutability of everything would prevent that).

I toyed with the idea of making the getGuess and giveHints functions take an extra parameter that represents the number of guesses so far (let's call it numGuesses), and, on every call to those methods, pass (numGuesses+1). But I couldn't get that to work (not to mention I don't even know if that would work).

My code is below. Any suggestions would be really appreciated. I'm mostly looking for ideas, but feel free to post actual code as well. Also, feel free to let me know if my code sucks and how I could improve it if you notice anything heinous (I've only been programming functionally for a couple weeks!)

    import System.Random
    import System.IO
    import Control.Monad

    main = do
        gen <- getStdGen
        let (ans,_) = randomR (1,100) gen :: (Int,StdGen)
        putStrLn $ "I'm thinking of a number between 1 and 100..."
        getGuess ans
        putStrLn "You guessed it in __ guesses!"
        putStr "Play again? "
        hFlush stdout
        desire <- getLine
        when ((desire !! 0) `elem` ['y','Y']) $ do
            putStrLn ""
            newStdGen
            main

    getGuess ans = do   
        putStr "Your guess? "
        hFlush stdout
        guessStr <- getLine
        giveHints ans (read guessStr)

    giveHints ans guess = do
        when (ans /= guess) $ do
           if ans > guess 
               then putStrLn "It's higher." 
               else putStrLn "It's lower."
           getGuess ans

Note: I am using hFlush stdout because I'm using line buffering and, without it, the order of some of the interactions are not what one would expect.

2 Answers
Related