为什么Haskell不相关模式匹配的绑定标识符?

时间:2016-09-18 18:54:46

标签: haskell pattern-matching

f x zero = Nothing
f x y = Just $ x / y 
  where zero = 0 

文字绑定标识符zero只是在警告Pattern match(es) are overlapped之后匹配所有标识符。

4 个答案:

答案 0 :(得分:6)

Haskell的语法是如何工作的; 模式中的每个小写 - 初始变量名称(重新)绑定该名称。任何现有绑定都将阴影

但即使不是这种情况,第一种选择也不会看到zero的绑定,因为Haskell的语法是如何工作的。类似的事情发生在以下版本中:

f = \v1 v2 -> case (v1, v2) of
                  (x, zero) -> Nothing
                  (x, y)    -> Just $ x / y
                    where zero = 0

where子句仅适用于 一个替代,而不是整个备选列表。该代码几乎与

相同
f = \v1 v2 -> case (v1, v2) of
                  (x, zero) -> Nothing
                  (x, y)    -> let zero = 0 in Just $ x / y

答案 1 :(得分:5)

如果绑定标识符在模式匹配中具有与未绑定标识符不同的语义,则可能非常容易出错,因为绑定新标识符可能会使标识符位于范围内的任何位置都会混乱。

例如,假设您正在导入某个模块Foo(不合格)。现在,由于某种原因,模块Foo被更改为添加绑定<input type="hidden" ng-model="dependentid" /> 。现在在你的模式匹配中,你突然将第一个参数与42进行比较,而不是将其绑定到x = 42。这很难找到错误。

因此,为了避免这种情况,标识符模式具有相同的语义,无论它们是否已经绑定到某处。

答案 2 :(得分:4)

因为它们非常脆弱。这算什么?

f x y z = 2*x + 3*y + z

您希望这等于

吗?
f x 3 z = 2*x + 9 + z
f _ _ _ = error "non-exhaustive patterns!"

只是因为在同一个1000+线路模块中某处定义了y = 3

还要考虑这个:

import SomeLibrary
f x y z = 2*x + 3*y + z

如果将来的版本SomeLibrary定义y怎么办?我们不希望突然停止工作。

最后,如果Eq没有y个实例,该怎么办?

y :: a -> a
y = id

f :: a -> (a -> a) -> a
f x y = y x
f x w = w (w x)

当然,这是一个人为的例子,但运行时无法比较输入函数以检查它是否等于y

为了消除歧义,一些像Swift这样的新语言使用了两种不同的语法。例如。 (伪代码)

switch someValue {
  case .a(x)     : ...  // compare by equality using the outer x
  case .b(let x) : ...  // redefine x as a new local variable, shadowing the outer one
}

答案 3 :(得分:2)

zero只是一个在模式中出现的变量,就像y在第二行中所做的那样。这两者没有区别。当一个变量出现在模式中时,会引入一个 new 变量。如果已经存在该变量的绑定,则新变量将隐藏旧变量。

因此,您无法在模式中使用已绑定的变量。相反,你应该做那样的事情:

f x y | y == zero = Nothing
  where zero = 0 
f x y = Just $ x / y 

请注意,我还移动了where子句,使其位于第一行的范围内。