Haskell AS绑定无可辩驳的模式

时间:2015-05-08 11:35:30

标签: haskell

我正在尝试将无可辩驳的模式和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  

3 个答案:

答案 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将不会被评估
  • 如果我们要求xyys,那么value将根据需要进行评估,以匹配y:ys(和三联)< / LI>
  • 如果我们要求zwws,则value将根据需要进行评估,以匹配y:ysw: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)无法作为空列表运行,即使我们实际上并未尝试访问模式中的头部或尾部。