To test my skills in Haskell, I decided I wanted to implement the very first game you find in Land of Lisp / Realm of Racket. The "Guess My Number" game. The game relies on mutable state to run, as it constantly has to update upper and lower bounds for the program to home in on the value the user is thinking of.
It goes a little something like this:
> (guess)
50
> (smaller)
25
> (bigger)
37
Now, this sort of thing (to my knowledge) isn't entirely possible in Haskell, calling some function from the REPL that modifies global mutable state, then prints the result immediately after, as it violates the principle of immutability. Therefore all of the interaction must live inside of an IO
and/or State
monad. And that's where I'm stuck.
I can't seem to be able to wrap my mind around combining the IO
monad and the State
monad, so I can get input, print results and modify state, all in the same function.
Here's what I got so far:
type Bound = (Int, Int) -- left is the lower bound, right is the upper
initial :: Bound
initial = (1, 100)
guess :: Bound -> Int
guess (l, u) = (l + u) `div` 2
smaller :: State Bound ()
smaller = do
bd@(l, _) <- get
let newUpper = max l $ pred $ guess bd
put $ (l, newUpper)
bigger :: State Bound ()
bigger = do
bd@(_, u) <- get
let newLower = min u $ succ $ guess bd
put $ (newLower, u)
All I need to do now, is to devise a way to
- print initial guess
- receive command wanting smaller/bigger number
- modify state accordingly
- call the function recursively so it guesses again
How do I combine IO
and State
in an elegant way to achieve this?
Note: I'm aware that this can probably be achieved without the use of state at all; but I want to make it stay true to the original