2016-07-24 43 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