模式中的警卫匹配让我们绑定

时间:2015-03-07 11:56:57

标签: haskell

我对此的语义感到惊讶(下面的第三个表达式)。从这里开始:

Prelude> let (a,b) = (0,0) in (a,b)
(0,0)

没关系。现在加一个警卫,它仍然很好:

Prelude> let (a,b) | True = (0,0) in (a,b)
(0,0)

现在改变警卫,并感到惊讶:

Prelude> let (a,b) | a == b = (0,0) in (a,b)
(^CInterrupted.

为什么? - 这有效:

Prelude> case (0,0) of (a,b) | a == b -> (a,b)
(0,0)

2 个答案:

答案 0 :(得分:8)

let中的守卫 - s表示“如果条件评估为True,则将lhs绑定到rhs”。由于Haskell let - s是递归的,let (a,b) | a == b = (0,0) in (a,b)首先尝试评估a == b ab指向刚刚定义的变量,这可能是通过再次检查防护中的a == b进行评估,这会导致循环。这是一个循环,出于同样的原因let x = x in x在尝试强制x时导致循环。

答案 1 :(得分:6)

let等同于

let (a,b) = if a==b 
            then (0,0) 
            else error "non exhaustive..."

更清楚地显示了它的递归性质。

您的误解来自您的允许转换,这在有警卫(或递归)的情况下是不正确的。要了解原因,请考虑如何翻译以下内容:

let (a,b) | condition1 = (0,0)
          | condition2 = (1,1)

上述内容无法重写为case (0,0) of (a,b) -> ...case (1,1) of (a,b) -> ...,因为您需要在(0,0)(1,1)之间进行选择之前评估条件。