我正在尝试将无可辩驳的模式和AS绑定用于评估反向波兰表示法表达式的函数。
这是我的代码:
resolveRPN :: String -> [Integer]
resolveRPN = foldl helper [] . words
where
helper ~stack@(x1:x2:xs) el
| el == "+" = (x2 + x1) : xs
| el == "-" = (x2 - x1) : xs
| el == "*" = (x2 * x1) : xs
| el == "/" = (x2 `div` x1) : xs
| otherwise = (read el) : stack
如果你给出一个少于2个元素的列表,那么无论如何都会失败,但这应该只用于“+ - * /”。 如果函数应用于“10 10”,它应该只使用“否则”并使用AS绑定“堆栈”并且不应该尝试将其分解为构造函数,但似乎它不能像那样工作。
例如,如果我使用帮助器折叠并使用[0,0]作为累加器,即使不需要此值,也可以正常工作。
有人可以解释为什么这段代码仍会引发“无可辩驳的模式”除外?或者Haskell如何评估这个?
以下是简化代码:
notWorking :: [Int]
notWorking = helper [] "10"
where
helper ~stack@(x1:x2:xs) el = (read el) : stack
working:: [Int]
working = helper [] "10"
where
helper ~stack el = (read el) : stack
答案 0 :(得分:3)
无法反驳的模式仅适用于stack@(x1:x2:xs)
,因此当您尝试提取stack
时,这将自动评估(x1:x2:xs)
。
此问题可以使用irrefutable仅针对模式匹配进行修复,但不能作为定义hepler
的绑定使用,如下所示:
helper stack@ ~(x1:x2:xs) el
| el == "+" = (x2 + x1) : xs
| el == "-" = (x2 - x1) : xs
| el == "*" = (x2 * x1) : xs
| el == "/" = (x2 `div` x1) : xs
| otherwise = (read el) : stack
这对于有效的表达式永远不会失败。
答案 1 :(得分:1)
拇指规则是:
~p
匹配所有内容x
中的变量p
,请考虑p
的句法树中可从x
到达的所有构造函数,除了向下移动 跨~
:匹配的值将被评估以匹配这些构造函数示例:
case value of ~(x,y:ys,~(z,w:ws)) -> ...
value
将不会被评估x
或y
或ys
,那么value
将根据需要进行评估,以匹配y:ys
(和三联)< / LI>
z
或w
或ws
,则value
将根据需要进行评估,以匹配y:ys
和w:ws
(以及三联和配对)试验:
> case undefined of ~(x,y:ys,~(z,w:ws)) -> "hello"
"hello"
> case (3,undefined,(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> x
*** Exception: Prelude.undefined
> case (3,[],(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> x
*** Exception: Irrefutable pattern failed for pattern (x, y : ys, ~(z, w : ws))
> case (3,[0],(4,undefined)) of ~(x,y:ys,~(z,w:ws)) -> x
3
> case (3,[0],(4,[])) of ~(x,y:ys,~(z,w:ws)) -> x
3
> case (3,[],(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> z
*** Exception: Irrefutable pattern failed for pattern (x, y : ys, ~(z, w : ws))
> case (3,[0],(4,[])) of ~(x,y:ys,~(z,w:ws)) -> z
*** Exception: Irrefutable pattern failed for pattern (z, w : ws)
在我看来,如果~
下的每个子模式都表现得好像它上面有~
那么语义可能会更好。例如。如果~(x,y:ys)
等同于~(x,~(y:ys))
。但是,当前的语义确实允许更大的灵活性。
该规则即使存在&#34; as&#34;图案。例如,在
中case value of a@ ~(x,y:ys,~b@(z,c@(w:ws))) -> ...
要求a
不会评估value
,但要求任何其他变量
将导致value
被评估,以匹配三元组。
此外,要求任何x,y,ys
也会导致评估匹配
y:ys
中的列表构造函数。相反,匹配b
或任何z,c,w,ws
会导致value
进一步评估,因此要匹配(z,c@(w:ws))
对以及列表w:ws
,属于第二个~
。
--Here is an example with "as" pattern outside that will succeed
> case (1,[],(2,[3])) of a@ ~(x,y:ys,~b@(z,c@(w:ws))) -> a
(1,[],(2,[3]))
--This will fail because the triple as well as y:ys will be evaluated along a
> case (1,[],(2,[3])) of ~a@(x,y:ys,~b@(z,c@(w:ws))) -> a
*** Exception: Irrefutable pattern failed for pattern a@(x, y : ys, ~b@(z, c@(w : ws)))
在您的代码中,您只需将&#34; as&#34;在~
之外绑定像这样:
helper stack@ ~(x1:x2:xs) el
| el == "+" = (x2 + x1) : xs
| el == "-" = (x2 - x1) : xs
| el == "*" = (x2 * x1) : xs
| el == "/" = (x2 `div` x1) : xs
| otherwise = (read el) : stack
并且可以正常用于任何有效的RPN输入。
答案 2 :(得分:0)
当我们尝试打印结果列表时,无法反驳的模式失败:
head $ resolveRPN "2 4 +" -- 6, no error
resolveRPN "2 4 +" -- error
在上面的示例中,我们在结果列表的末尾没有正确的[]
。相反,我们有一个无可辩驳的(:)
模式,它会抛出一个错误。换句话说,~(x:xs)
无法作为空列表运行,即使我们实际上并未尝试访问模式中的头部或尾部。