haskell:RPN 计算器

发布于 2024-12-11 18:50:30 字数 1044 浏览 0 评论 0原文

我想开发一种堆栈管理系统。该列表以空 [] 开始,用户可以输入数字,它们将被添加到列表中,以及二元运算,这将从列表中取出前两个数字并执行操作,然后将其放回列表中。 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萌吟 2024-12-18 18:50:30

走在正确的道路上;让我们看一下我建议对您的代码进行的一些更改。

您的 add1 函数非常接近,但有两个小问题 - 第一个是您提供的模式匹配:为了语法正确,您需要将整个匹配放在括号内。第二个是第二个缺点(冒号)。 cons 的类型为 a -> [一]-> [a],所以它与(x+y)作为第一个参数完美配合;但是,由于 xs 已经具有类型 [Int],因此您无需提供 : []

add1 (x:y:xs) = (x+y) : xs

接下来,由于您完全处理 IntInt 列表,因此在这种情况下使用某种类型 a 没有意义。

push :: [Int] -> Int -> [Int]

最后,您的主力功能。由于 Haskell 中缺乏循环构造,因此执行用户输入循环的方法(也称为 REPL< /a>) 是通过递归实现的。因此,接受参数是有意义的。让我们将其设为您的 [Int] 堆栈。从 stdin 读取一行作为字符串的函数是 getLine,其类型为 IO String。最后,您实际上必须处理该输入。为简单起见,我只是将该逻辑包含在 xclcase 语句中,但也可以使用 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,如 这个答案。 reads 返回一个包含单个条目的列表 - 一个包含解析后的数字和剩余字符串的元组,或一个空列表(表示读取失败)。例如:

      x -> case (reads x) of
        [(num,_)] -> xcl $ push st num
        _ -> xcl st

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 of a -> [a] -> [a], so it works perfectly with (x+y) as the first parameter; however, since xs has type [Int] already, you don't need to supply : [].

add1 (x:y:xs) = (x+y) : xs

Next, because you are dealing entirely with Ints and lists of Ints, using some type a does not make sense in this context.

push :: [Int] -> Int -> [Int]

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 is getLine, which has type IO String. Finally, you actually have to handle that input. For simplicity, I've just included that logic in a case statement in xcl, but it could as well have been done using dispatch 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 of 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

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 of read, 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:

      x -> case (reads x) of
        [(num,_)] -> xcl $ push st num
        _ -> xcl st
毅然前行 2024-12-18 18:50:30
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
  1. stack 不能是顶级常量,因为我们需要操作它。因此我们将其作为 xcl 的参数。
  2. 使用 getLine 读取一行文本,因为我们不知道是将其解释为运算符名称还是数字。
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
  1. stack cannot be a top level constant, because we will want to manipulate it. So we make it a parameter to xcl instead.
  2. Use 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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文