我对此的语义感到惊讶(下面的第三个表达式)。从这里开始:
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)
答案 0 :(得分:8)
let
中的守卫 - s表示“如果条件评估为True,则将lhs绑定到rhs”。由于Haskell let
- s是递归的,let (a,b) | a == b = (0,0) in (a,b)
首先尝试评估a == b
a
和b
指向刚刚定义的变量,这可能是通过再次检查防护中的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)
之间进行选择之前评估条件。