Haskell中的变量

5
为什么以下Haskell脚本不能按预期工作?
find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (k,v) <- t]

给定 find 'b' [('a',1),('b',2),('c',3),('b',4)],解释器返回的结果是 [1,2,3,4] 而不是 [2,4]。为了让它正常工作,需要引入一个新变量,下面称为 u

find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (u,v) <- t, k == u]

有人知道为什么第一种变体没有产生期望的结果吗?


跟我重复一遍:Haskell 中没有变量。;-) 这些是符号或标识符。变量意味着可变性。在 Haskell 中,一切都是不可变的。 - Konrad Rudolph
9
@Konrad Rudolph: Haskell 98 Report中到处都使用"variable"这个术语。重要的是要注意,这并不意味着你可能期望的那样,但我认为比标准文档更苛刻并不一定有帮助。 - Travis Brown
4
@Konrad Rudolph: 当然不是开玩笑!我在这里找到了一整个关于变量的章节在某本Haskell书中 - C. A. McCann
1
@Travis Brown:这基本上意味着与在一阶逻辑公式中由量词绑定的变量相同...我无法想象为什么有人会期望其他的东西!;) - C. A. McCann
阅读find的第一个版本时,我实际上期望的是[1,2,3,4]... 必须也读取函数名称。 - gawi
哦,我从来不知道。为自己辩护,其他语言确实有区别。 - Konrad Rudolph
3个回答

14

根据Haskell 98报告

 

通常情况下,列表推导中的绑定会屏蔽外部作用域中的同名绑定;例如:

 

[ x | x <- x, x <- x ] = [ z | y <- x, z <- y]

另外一点:如果使用-Wall编译(或具体使用-fwarn-name-shadowing选项),则会得到以下警告:

Warning: This binding for `k' shadows the existing binding
           bound at Shadowing.hs:4:5

通常使用-Wall是一个好主意 - 它通常会突出显示在可能令人困惑的情况下正在发生的事情。


我认为问题不在于遮蔽。而是关于模式中标识符的含义 - 它不匹配具有该标识符的变量的值,而是匹配任何内容并将该值绑定到具有该标识符的新变量上。 - newacct

11

第一个例子中的模式匹配(k,v) <- t创建了两个新的本地变量vk,这些变量被填充了元组t的内容。模式匹配不会将t的内容与已经存在的变量k进行比较,而是创建了一个新变量k(它隐藏了外部的那个变量)。

通常,在模式中永远不会发生"变量替换",模式中的任何变量名都会创建新的本地变量。


3

您只能在字面值和构造函数上进行模式匹配。
您无法匹配变量。 这里阅读更多信息。

话虽如此,您可能会对视图模式感兴趣。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接