2016-07-24 55 views
2

我正在學習Haskell。這是一個簡單的例子,但我想理解爲什麼我不能在下面的例子中使用lambda函數內部的模式匹配(即,爲什麼filterfold'函數運行但filterfold'給出運行時錯誤):lambda內模式匹配

-- Runs 
filterfold' :: (a -> Bool) -> [a] -> [a] 
filterfold' p zs = foldr (\y zs -> if (p y) then y:zs else zs) [] zs 

-- Runtime error: Non-exhaustive patterns in lambda 
filterfold :: (a -> Bool) -> [a] -> [a] 
filterfold p (z:zs) = foldr (\y (z:zs) -> if (p y) then y:(z:zs) else (z:zs)) [] (z:zs) 

回答

4

你可以使用它,但因爲編譯器會告訴你,你缺失的情況下(當輸入爲[]

看看你說z:zs它會嘗試匹配此模式與輸入列表 - 如果你

  • 輸入[1,2,3] = 1:[2,3]z=1zs=[2,3]
  • 但是當輸入[]你不能得到一個zzs使z:zs = [](技術上它們是基於列表的數據類型的不同構造函數)

因此,在運行時,它會不知道當它看到[]並拋出異常時如何處理這種情況/模式。

,如果你在你的例子仔細觀察你會看到,你從來沒有實際使用的部分反正

(意爲zzs - 你只使用他們作爲z:zs再次),所以我不能告訴你如何做的更好

反正你可以使用case - 表達的拉姆達內部:

... = foldr (\ x zs = case zs of 
         z:zs -> ... 

,或者您可以使用LambdaCase擴展使它有點短。

+0

因此,filterfold函數參數中的zs在範圍內,而不是使用filterfold中的'z',它會嘗試在lambda中本地執行模式匹配? – Daniel

+1

是的lambda中的'z'和'zs'將是不同的('foldr'將提供*它們) - 這就是爲什麼你不應該重複使用lambda參數的參數/參數名 - 你*引入*這些名稱你的lambda會隱藏一次從外部範圍 - 所以如果你想(重新)從'filterfold'的外部範圍使用'z'和'zs',你應該把它重命名爲'foldr(\ y ys - > ...)'(或者任何你喜歡的名字都不同於'p','z','zs'和'y';)) – Carsten

+0

但是請注意:如果你實際上不需要第二個參數函數(lambda)給你'foldr',那麼你可能並不需要'foldr',因爲如果它只是在列表的'head'上操作,如果它不是空的或者默認爲第二個'foldr'的參數 – Carsten