2017-10-07 33 views
2

我是新来的Haskell所以它可能是显而易见的,但我没有Prolog的广泛所以我很困惑这一个...Haskell的元组不能与函数参数匹配

当使用GHCI,我创建了以下功能(1):

Prelude> let find k t = head [v | (k',v) <- t, k == k'] -- Definiton of find 
find :: Eq a1 => a1 -> [(a1, a)] -> a 

Prelude> find 2 [(1,11),(2,22)] -- Invocation of find 
22 

这是预期的。然后我试图从定义中删除的K”:

Prelude> let find2 k t = head [v | (k,v) <- t] 
find2 :: t -> [(t1, a)] -> a 

Prelude> find2 2 [(1,11),(2,22)] 
11 

当时我很惊讶地看到1实际相匹配的值2。 只是可以肯定我是不是希望能为不可能,于是我也尝试以下列来确认部分匹配可能在Haskell,这看起来确实是这样的:

Prelude> head [v | (2,v) <- [(1,11),(2,22)]] 
22 

我还注意到一个差异在函数声明中。我添加了所需的信息,因此findfind2的声明看起来完全一样。但结果仍然是断开的(2,_) matchnig (1,11)

Prelude> let find2 :: Eq a1 => a1 -> [(a1, a)] -> a; find2 k t = head [v | (k,v) <- t] 
find2 :: Eq a1 => a1 -> [(a1, a)] -> a 

Prelude> find2 2 [(1,11),(2,22)] 
11 

如何2通过任何手段来匹配1

(1)上述函数来源于优良书“在Haskell编程”第93页

+4

简单的讲,序言不统一,Haskell只做模式匹配。 – chi

+4

无聊的实用建议:在学习时使用'-Wall'会非常有帮助(以及以真实代码捕捉问题) – jberryman

回答

11

是,Haskell的模式匹配是来自前导图案匹配根本不同的。

在Haskell中,模式中的一个变量指的是一个新的变量,它将被匹配项绑定,而不是必须匹配的现有变量。因此,表达式:

let x = 5 in case (1,2) of (x,y) -> "matched!" -- gives "matched!" 

将始终评估为“匹配!”。这是因为在(x,y)x得到新鲜势必1,不与x的“现有”,外定义的值进行比较,你可以在这里看到:

let x = 5 in case (1,2) of (x,y) -> x  -- gives "1" 

的行为是数字常量不同:

case (1,2) of (5,y) -> "matched!" -- match fails 

以及用于其他的构造:

case (True,2) of (False,y) -> "match!" -- match fails 

其不是 “重新绑定”而是必须匹配模式匹配才能成功。这是字母数字构造函数以大写字母开头的许多原因之一:否则,要确定模式是否与现有构造函数匹配或重新绑定到新变量将非常困难。

这适用于图案在任何上下文匹配,无论是CASE表达式如上或函数的定义是这样的:

let x = 5 
f x = "hi"  -- defines `f` for any `x`, not just `f 5` 

或列表理解像你的例子。在该表达式中:

[v | (k,v) <- [(1,2),(3,4)]] -- gives [(1,2),(3,4)] 

变量kv永远是新鲜的,所以将结合到任何元组,尽管kv任何外,现有的定义。如果您打开-Wall(特别是-Wname-shadowing)的警告,这会提醒您注意阴影绑定。如果你有一个常数(或其他构造)代替k,它的行为是不同的:

[v | (3,v) <- [(1,2),(3,4)]] -- only gives [(3,4)] 

你可以不喜欢它,但是这只是Haskell的工作方式。

+0

“否则,要确定是否” - > Meh,这只是范围检查将非常困难。范围感知语法突出显示可以处理这种情况(例如参见Agda) – gallais

0

感谢您的帮助!经过一些搜索后,我也发现这个答案有帮助:How can I re-assign a variable in a function in Haskell?

创建一个具有相同名称的新变量,它会隐藏前一个变量。但第一个变量仍然存在,在某些情况下仍然可以访问...

所以这确实是远远序言和是以下标志是珍贵的帮助:

Prelude> :set -fwarn-name-shadowing