RPN计算器实现中的Haskell问题

时间:2014-02-10 13:30:46

标签: haskell rpn

我正在尝试在Haskell中实现RPN计算器。这是Learn You a Haskell的练习。 这是我的代码:

import Data.List
solveRPN :: String -> Int
solveRPN str = head $ foldl putStack [] (words str) 
         where putStack accumulator token 
            | token == "+" = pFunction (+)
            | token == "-" = pFunction (-)
            | token == "*" = pFunction (*)
            | token == "/" = pFunction (`div`)
            | otherwise    = accumulator ++ [read token :: Float]
            where pFunction function =  (int $ init accumulator) ++ [function argu1 argu2]
                  argu1 = last accumulator
                  argu2 = last $ init accumulator

函数solveRPN首先将字符串拆分为标记。 (例如:"4 3 2 + *" - > ["4","3","2","+","*"]) 然后,逐个令牌被推入堆栈。如果它遇到操作员,则操作员处理堆栈中的最后两个项目,然后将产生的值放回堆栈中。遍历整个列表时,堆栈中只剩下一个项目,这就是答案。

这里有一些问题:

  1. (int $ init accumulator)中我想取消堆栈中的最后两个元素。除(int $ init accumulator)之外还有其他选择吗?

  2. 代码无法通过编译。 GHC说“输入解析错误”(“ 在这一行:| token == "/" = pFunction ( div )。我怀疑问题可能来自pFunction。它的参数是一个运算符(或者我可以将其称为函数?)并且我不确定“函数作为函数的参数”在Haskell中是否合法。这合法吗?还有其他选择吗?

  3. 我在GHCi做了一些实验,发现了一些奇怪的事情:

  4. Prelude> let plus = (+) 
    Prelude> :t (+) 
    (+) :: Num a => a -> a -> a
    Prelude> :t plus 
    plus :: Integer -> Integer -> Integer
    

    为什么加号的类型与(+)的类型不同?

    感谢您的关注和耐心。 (:

2 个答案:

答案 0 :(得分:2)

  

(int $ init accumulator)

您的意思是init $ init accumulator吗?话虽这么说,你可以编写自己的dropLast2函数,它与init . init一样,但只遍历列表一次,如

dropLast2 :: [a] -> [a]
dropLast2 []       = []
dropLast2 [_]      = []
dropLast2 [_,_]    = []
dropLast2 (x:xs) = x : dropLast2 xs

  

代码无法通过编译。

        | token == "/" = pFunction (`div`)

您正在使用反引号(`)以使用具有两个参数的函数作为中缀函数。但是,通过在div周围使用括号,您会尝试立即取消它,这有点偏差和解析器错误。只需使用

        | token == "/" = pFunction div

代替。但是,有一件重要的事情。 div的类型是

div :: Integral a => a -> a -> a

但是,您的累加器是Float的列表。 div不可能对这些工作。但是,FloatFractional类的一个实例,因此您只需使用(/)

(/) :: Fractional a => a -> a -> a

因此得到

        | token == "/" = pFunction (/)

  

我在GHCi做了一些实验,发现了一些奇怪的事情

(+)Num课程的一部分。您的plus不属于任何函数,GHC会尝试推断其类型。然后monomorphism restriction开始。请参阅Type error while writing max function以获取更多信息。

答案 1 :(得分:1)

关于你的第一个问题:

我得到的印象是你正在使用错误的方式。如果在堆栈上推送元素,则应使用:运算符将其添加到列表中。弹出前两个元素然后变成drop 2 stack,这更好,我想。

这样做也会更有效率,因为:是一个恒定时间操作,而++是第一个参数大小的线性(即你的堆栈大小)。