实际上问题不是空的子列表:
ghci> multiply [[1, 2, 3], [4, 5, 6]]
[[-1,-2,-3],[-4,-5,-6]*** Exception: <interactive>:2:1-50: Non-exhaustive patterns in function multiply
您使用 处理子列表[n * (-1) | n <-x]
,列表推导在空列表上工作正常;这个将找不到要乘以的元素-1
,因此会产生一个空列表。您可以在引用的输出中看到空列表;之后它甚至会继续产生更多的输出,这很确定它在处理空子列表时没有抛出异常。
所以有什么问题?好吧,让我们看看错误消息实际上说的是什么:Non-exhaustive patterns in function multiply
. 这意味着函数中的某处代码multiply
正在执行模式匹配,而被匹配的值实际上并不适合您提供的任何模式。好吧,在你的整个函数中只有一个地方可以进行任何模式匹配,那就是multiply (x: xs)
, 所以这一定是问题所在!
现在列表总是空列表[]
或表单item : rest_of_list
(其中:
是列表数据类型的另一个构造函数)。你只:
为表单提供了一个模式,所以multiply
如果你将它应用到一个空列表肯定会抛出一个错误。这立即向我们展示了问题,即使没有将其与您的案例中实际发生的情况联系起来(我稍后会做)。
如何解决?您需要说明multiply []
应该产生什么结果。通常,当您编写列表的递归函数时,您希望从这种形式开始:
func [] = _
func (x : xs) = _
然后填空。有时,有其他情况会很方便,[x]
或者[x, y]
如果您需要专门处理具有 1 个或 2 个元素的列表。只有极少数情况下您才应该忽略 的情况[]
,因为如果您这样做,您的函数肯定会抛出您在某些调用的问题中看到的异常。
在这种情况下,multiply
只需将其 list-of-list 参数的所有子列表中的所有值取反,因此很容易看出它应该对空的子列表执行什么操作:只需返回一个空列表。所以我们会有:
multiply [] = []
multiply (x: xs) = [n * (-1) | n <-x]: multiply xs
(如果您将它输入到 GHCi 而不是文件中,则需要使用多行模式来输入它; enter:{
启动多行模式,然后输入定义的所有行,然后 enter:}
给出所有你的代码行一次到编译器)
现在,还有一个更明显的问题。你没有打电话multiply []
,你打电话multiply [[1,3,6.7,7.0],[],[1,8.22,9,0]]
。那么为什么它抱怨参数与空列表的模式不匹配呢?原始调用没有,但是每次您调用原始调用时,它都会multiply
在较小的列表中调用自己!
它与[ [1,3,6.7,7.0], [], [1,8.22,9,0] ]
模式匹配x : xs
,结果为x = [1,3,6.7,7.0]
and xs = [ [], [1,8.22,9,0] ]
。然后它调用multiply xs
.
因此,在第二次调用中,我们将匹配[ [], [1,8.22,9,0] ]
pattern x : xs
。在本次评测中,x = []
和xs = [ [1,8.22,9,0] ]
。我们multiply xs
再次调用这个版本的xs
.
现在在第三次调用中,我们匹配[ [1,8.22,9,0] ]
pattern x : xs
。为了成功,我们必须同时找到 x
和xs
。单个元素列表的尾部是空列表,所以x = [1,8.22,9,0]
but xs = []
。然后我们multply xs
再次调用这个版本的xs
,这就是问题所在。现在我们尝试匹配[]
该模式x : xs
,但我们不能,但也没有其他模式可以尝试,所以我们只得到Non-exhaustive patterns in function multiply
.