haskell:RPN 计算器
我想开发一种堆栈管理系统。该列表以空 [] 开始,用户可以输入数字,它们将被添加到列表中,以及二元运算,这将从列表中取出前两个数字并执行操作,然后将其放回列表中。 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
但我什至不知道我是否朝着正确的方向前进。任何帮助都会很棒。谢谢。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您走在正确的道路上;让我们看一下我建议对您的代码进行的一些更改。
您的
add1
函数非常接近,但有两个小问题 - 第一个是您提供的模式匹配:为了语法正确,您需要将整个匹配放在括号内。第二个是第二个缺点(冒号)。 cons 的类型为a -> [一]-> [a]
,所以它与(x+y)
作为第一个参数完美配合;但是,由于xs
已经具有类型[Int]
,因此您无需提供: []
。接下来,由于您完全处理
Int
和Int
列表,因此在这种情况下使用某种类型a
没有意义。最后,您的主力功能。由于 Haskell 中缺乏循环构造,因此执行用户输入循环的方法(也称为 REPL< /a>) 是通过递归实现的。因此,接受参数是有意义的。让我们将其设为您的
[Int]
堆栈。从 stdin 读取一行作为字符串的函数是getLine
,其类型为IO String
。最后,您实际上必须处理该输入。为简单起见,我只是将该逻辑包含在xcl
的case
语句中,但也可以使用dispatch
或类似的函数(事实上,如果你的 RPN 计算变得更复杂,这会有它的优点)。每种情况的操作应该使用修改后的堆栈递归到您的 xcl“循环”中。当您退出时,它应该直接退出 - 这是return
的一个很好的用途。事实上,您可以更进一步并防止异常 - 当用户传递一些非函数、非数字字符串时会发生什么?上面的代码将失败,并出现“无解析”异常。解决这个问题的最佳方法是使用
reads
代替read
,如 这个答案。 reads 返回一个包含单个条目的列表 - 一个包含解析后的数字和剩余字符串的元组,或一个空列表(表示读取失败)。例如:You are on the right path; lets take a look at some changes to your code I would suggest.
Your
add1
function 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, sincexs
has type[Int]
already, you don't need to supply: []
.Next, because you are dealing entirely with
Int
s and lists ofInt
s, using some typea
does 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 acase
statement inxcl
, but it could as well have been done usingdispatch
or 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
reads
in place ofread
, as is discussed in this answer.reads
returns 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:stack
不能是顶级常量,因为我们需要操作它。因此我们将其作为xcl
的参数。getLine
读取一行文本,因为我们不知道是将其解释为运算符名称还是数字。stack
cannot be a top level constant, because we will want to manipulate it. So we make it a parameter toxcl
instead.getLine
to read a line of text, because we don't know whether we want to interpret it as an operator name or as a number.阅读此http://learnyouahaskell.com/functionly-solving-problems#reverse -抛光符号计算器。这可能会有帮助。
Read this http://learnyouahaskell.com/functionally-solving-problems#reverse-polish-notation-calculator . It may be helpfull.