我是Haskell的新手,所以这可能是显而易见的,但我做了广泛的Prolog所以我对这个感到困惑......
使用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
我很惊讶地发现价值2
实际上与1
匹配。
为了确保我不希望不可能,我也尝试以下内容以确认在Haskell中可以进行部分匹配,看起来确实如此:
Prelude> head [v | (2,v) <- [(1,11),(2,22)]]
22
我还注意到函数声明的不同之处。我添加了所需的信息,因此find
和find2
的声明看起来完全相同。但结果仍然被打破(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页
答案 0 :(得分:11)
是的,Haskell模式匹配与Prolog模式匹配根本不同。
在Haskell中,模式中的变量引用将由匹配绑定的新变量,而不是必须匹配的现有变量。所以,表达式:
let x = 5 in case (1,2) of (x,y) -> "matched!" -- gives "matched!"
将始终评估为&#34;匹配!&#34;。这是因为x
中的(x,y)
刚刚与1
绑定,而不是与{{1}的现有&#34;外部定义的值相比较你可以在这里看到:
x
数字常量的行为不同:
let x = 5 in case (1,2) of (x,y) -> x -- gives "1"
和其他构造函数:
case (1,2) of (5,y) -> "matched!" -- match fails
不是&#34;重新绑定&#34;但必须匹配模式匹配才能成功。这是字母数字构造函数以大写字母开头的众多原因之一:否则,确定模式是否与现有构造函数匹配或重新绑定到新变量将非常困难。
这适用于任何上下文中的模式匹配,无论是上面的案例表达式还是像这样的函数定义:
case (True,2) of (False,y) -> "match!" -- match fails
或列出您的例子的理解。在表达式中:
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)]
和k
将始终是新鲜的,因此将绑定到任何元组尽管 v
或{的任何外部现有定义{1}}。如果您使用k
(特别是v
)启用警告,则会提醒您注意阴影绑定。如果用常量(或其他构造函数)替换-Wall
,它的行为会有所不同:
-Wname-shadowing
你可能不喜欢它,但这只是Haskell的工作方式。
答案 1 :(得分:0)
感谢您的帮助!经过一些搜索,我发现这个答案很有用:How can I re-assign a variable in a function in Haskell?
创建一个具有相同名称的新变量,该变量将隐藏前一个变量。但是第一个变量仍然存在,在某些情况下仍然可以访问......
所以这确实远离Prolog,是的,以下标志是非常有用的:
Prelude> :set -fwarn-name-shadowing