Reputation: 641
As an exercise I'm writing a command-line RPN calculator in Haskell. The idea is it will prompt for input (a number or operator) and print out the new stack. My plan is to store the list of numbers in a state monad, and perform calculations against that list. For example:
> 4
[4]
> 3
[3,2]
> 5
[5,3,2]
> +
[8, 2]
and so on.
I'm starting with just trying to build up the list in the State monad with input & output on each entry. I'm already stuck due to the combination of IO & State in the same function. My problem is, I also need to recurse on the input, to keep the prompt going after the first number is input.
Here is my code so far:
module Main where
import Control.Monad.State
addEntry :: Int -> State [Int] Int
addEntry entry = do
entries <- get
put (entry : entries)
return entry
mainLoop :: [Int] -> IO ()
mainLoop entries = do
entry <- readLn
newEntries <- execState (addEntry entry) entries
print newEntries
mainLoop newEntries
main :: IO ()
main = do
print $ mainLoop []
and here is the compiler error I'm currently getting:
src/Main.hs@14:28-14:42 Couldn't match type [Int] with ‘IO [Int]’
Expected type: State (IO [Int]) Int
Actual type: State [Int] Int …
src/Main.hs@14:44-14:51 Couldn't match expected type ‘IO [Int]’ with actual type [Int] …
Any tips on how to structure these functions such that I'm not combining IO & State?
Upvotes: 4
Views: 515
Reputation: 2717
I'm not sure if you're using state because you want to try it out, but you can achieve the state itself without the 'bother' of the state monad.
module Main where
addEntry :: Int -> [Int] -> [Int]
addEntry = (:)
mainLoop :: [Int] -> IO ()
mainLoop entries = do
entry <- readLn
let newEntries = addEntry entry entries
print newEntries
mainLoop newEntries
main :: IO ()
main = mainLoop []
Upvotes: 4