solveRPN :: String -> Double
solveRPN rpnString = head foldl . foldingFunction [] . words
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (x - y):ys
foldingFunction xs numberString = read numberString:xs
以上代码会产生以下错误。我已尝试将String
更改为[Char]
并替换单引号的双引号,但我一直收到此错误:
_01.hs:874:50: error: • Couldn't match type ‘Char’ with ‘[Char]’ Expected type: String Actual type: Char • In the first argument of ‘read’, namely ‘numberString’ In the first argument of ‘(:)’, namely ‘read numberString’ In the expression: read numberString : xs | 874 | foldingFunction xs numberString = read numberString:xs | ^^^^^^^^^^^^ Failed, 1 module loaded.
答案 0 :(得分:4)
“了解你的Haskell”一书中的原始解决方案如下所示
solveRPN :: (Num a, Read a) => String -> a
solveRPN = head . foldl foldingFunction [] . words
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
当我将其与您的代码段进行比较时,有两件事会导致错误:
1)您错误地将构图链中的合成运算符放错了地方。而不是这个
head foldl . foldingFunction [] . words
你需要这个
head . foldl foldingFunction [] . words
您可以在调用head
后使用foldingFunction
折叠后将其视为words
,其中每个“之后”都是撰写运算符。
2)您使用了合成,但仍然留下了参数rpnString
。如果要使用合成,则必须省略链接的参数。所以你可以省略参数:
solveRPN :: String -> Double
solveRPN = head . foldl foldingFunction [] . words
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
或者您可以省略构图链:
solveRPN :: String -> Double
solveRPN rpnString = head (foldl foldingFunction [] (words rpnString))
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
答案 1 :(得分:2)
错误实际上位于外部表达式中:
solveRPN rpnString = head foldl . foldingFunction [] . words
您在head
点击foldl
,这意味着我们希望foldl
具有某种类型[a -> b]
,因为head
可以获得该列表的第一个元素,该元素用于进一步处理。但foldl :: (b -> a -> b) -> b -> [a] -> b
当然不是一个清单。
另一个问题是这个子句有一个你忽略的显式参数rpnString
:看起来你做了一个 eta -reduction,但只删除了函数体中的参数,而不是在头脑中。
如果我们解决了这两个错误,我们就有了一个有效的解析器:
solveRPN :: String -> Double
solveRPN = head . foldl foldingFunction [] . words
foldingFunction :: [Double] -> String -> [Double]
foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (x - y):ys
foldingFunction xs numberString = read numberString:xs
但是存在语义错误:请注意x
是堆栈的顶部(您添加的最新数字),而y
是堆栈的子顶部。因此,如果执行减法,则需要在堆栈上按y - x
:
solveRPN :: String -> Double
solveRPN = head . foldl foldingFunction [] . words
foldingFunction :: [Double] -> String -> [Double]
foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
由于其他运算符是可交换的,因此使用运算符的顺序无关紧要。我们现在获得正确的结果。例如:
Prelude> solveRPN "14 25 * 13 - 2 *"
674.0
一些改进建议:
where
子句,这样您只能在本地定义foldingFunction
。Num
类型,在这种情况下,我们可以将解析器重用于所有类型的数字(Int
s,Float
等等。)。"*"
映射到乘法的逻辑,从而降低代码的复杂性。