I want to develop a sort of stack managing system. The list starts by being empty [] and a user can input numbers and they will be added to the list, as well as binary operations, which will take two first numbers from a list and perform the operation and then put it back on the list. EG:
[] : 3
[3] : 4
[4,3] : +
[7] : c
[] : 123
[123] : 3
[3,123] : *
[369] :
I cannot figure out how to process input from the console. I have this broken code:
import System.Environment
import System.Directory
import System.IO
import Data.List
stack = []
add1 :: [Int] -> [Int]
add1 [] = []
add1 [x] = [x]
add1 [x,y] = [(x+y)]
add1 x:(y:xs) = (x+y) : (xs : [])
--sub :: [Int] -> [Int]
--sub [] = []
--sub x:(y:xs) = (x-y) : xs
--mul :: [Int] -> [Int]
--mul [] = []
--mul x:(y:xs) = (x*y) : xs
--div :: [Int] -> [Int]
--div [] = []
--div x:(y:xs) = (x/y) : xs
c :: [Int] -> [Int]
c = []
push :: [Int] -> a -> [Int]
push [] a = [a]
push (x:xs) a = a : (x:xs)
dispatch :: [(String, Int -> IO ())]
dispatch = [ ("+", add)
-- , ("-", sub)
-- , ("*", mul)
-- , ("/", div)
]
xcl = do
print stack
answer <- readLine
But I don’t even know if I’m heading in the right direction. Any help will be great. Thank you.
You are on the right path; lets take a look at some changes to your code I would suggest.
Your
add1function is quite close, but you’ve got two small problems – the first is the pattern match you provide: to be syntactically correct, you need the whole match to be inside the parentheses. The second is the second cons (colon). cons has a type ofa -> [a] -> [a], so it works perfectly with(x+y)as the first parameter; however, sincexshas type[Int]already, you don’t need to supply: [].Next, because you are dealing entirely with
Ints and lists ofInts, using some typeadoes not make sense in this context.Finally, your workhorse function. Because of the lack of loop constructs in Haskell, the way to do a user input loop (also known an REPL) is through recursion. Because of this, it would make some sense to accept a parameter. Let’s make that your
[Int]stack. The function to read one line from stdin as a string isgetLine, which has typeIO String. Finally, you actually have to handle that input. For simplicity, I’ve just included that logic in acasestatement inxcl, but it could as well have been done usingdispatchor a similar function (In fact, if your RPN calculater becomes more complicated, this would have its merits). The action for each case should recurse into your xcl “loop” with a modified stack. When you quit, it should just exit – which is a good use ofreturn.In fact, you could take this one step further and protect against exceptions – what will happen when the user passes in some non-function, non-number string? The code above will fail, with a “no parse” exception. The best way around that is to use
readsin place ofread, as is discussed in this answer.readsreturns either a list with a single entry – a tuple containing a parsed number and a remaining string, or an empty list (indicating a failed read). For example: