我想开发一种堆栈管理系统。该列表以空[]开头,用户可以输入数字,它们将被添加到列表中,以及二进制操作,这将从列表中获取两个第一个数字并执行操作,然后将其放回列表中。 EG:
[] : 3
[3] : 4
[4,3] : +
[7] : c
[] : 123
[123] : 3
[3,123] : *
[369] :
我无法弄清楚如何处理来自控制台的输入。我有这个破碎的代码:
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
但我甚至不知道我是否朝着正确的方向前进。任何帮助都会很棒。谢谢。
答案 0 :(得分:4)
你是在正确的道路上;让我们来看看我建议的代码的一些变化。
你的add1
函数非常接近,但你有两个小问题 - 第一个是你提供的模式匹配:要在语法上正确,你需要整个匹配在括号内。第二个是第二个缺点(冒号)。 cons的类型为a -> [a] -> [a]
,因此它与(x+y)
完美匹配,作为第一个参数;但是,由于xs
已经有[Int]
类型,因此您无需提供: []
。
add1 (x:y:xs) = (x+y) : xs
接下来,因为您完全处理Int
和Int
的列表,所以使用某种类型a
在这种情况下没有意义。
push :: [Int] -> Int -> [Int]
最后,你的主力功能。由于Haskell中缺少循环结构,因此进行用户输入循环(也称为REPL)的方法是通过递归。因此,接受参数会有一定意义。让我们制作你的[Int]
堆栈。从stdin读取一行作为字符串的函数是getLine
,其类型为IO String
。最后,您实际上必须处理该输入。为简单起见,我刚刚将这个逻辑包含在case
中的xcl
语句中,但它也可以使用dispatch
或类似函数完成(事实上,如果你的RPN计算器变得更复杂,这将有其优点)。每个案例的操作应该使用修改后的堆栈递归到你的xcl“循环”中。当你退出时,它应该退出 - 这是return
的好用。
xcl :: [Int] -> IO ()
xcl st = do
print st
answer <- getLine
case answer of
"q" -> return ()
"c" -> xcl ([] ::[Int])
"+" -> xcl $ add1 st
x -> xcl $ push st $ read x
事实上,你可以更进一步防止异常 - 当用户传入一些非功能的非数字字符串时会发生什么?上面的代码将失败,并出现“无解析”异常。最好的方法是使用reads
代替read
,如this answer中所述。 reads
返回带有单个条目的列表 - 包含已解析数字和剩余字符串的元组,或者返回空列表(表示读取失败)。例如:
x -> case (reads x) of
[(num,_)] -> xcl $ push st num
_ -> xcl st
答案 1 :(得分:2)
xcl stack = do
print stack
answer <- getLine
case lookup answer dispatch of
Just function -> -- we have a function, apply it to the top of the stack
Nothing -> -- if we have a number, parse it and push it onto the stack
-- if not, issue an error
stack
不能是顶级常量,因为我们会想要操纵它。因此,我们将其作为xcl
的参数。getLine
读取一行文字,因为我们不知道是否要将其解释为运营商名称或数字。答案 2 :(得分:0)