2017-10-07 67 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