实际上问题不是空的子列表:
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) = _
然后填空。如果您需要专门处理具有 1 个或 2 个元素的列表,有时使用 [x] 或 [x, y] 等其他情况会很方便。只有极少数情况下您应该忽略 [] 的情况,因为如果您这样做,您的函数将肯定抛出您在某些调用的问题中看到的异常。
在这种情况下,multiply 只是将其 list-of-list 参数的所有子列表中的所有值取反,因此很容易看出它应该对 empty 列表做什么子列表:只返回一个空列表。所以我们会有:
multiply [] = []
multiply (x: xs) = [n * (-1) | n <-x]: multiply xs
(如果您将其输入 GHCi 而不是文件,则需要使用多行模式来输入;输入 :{ 以启动多行模式,然后输入定义的所有行,然后输入:} 一次将所有代码行提供给编译器)
现在,还有一个更明显的问题。你没有打电话给multiply [],你打电话给multiply [[1,3,6.7,7.0],[],[1,8.22,9,0]]。那么为什么它抱怨参数与 empty 列表的模式不匹配?原来的调用没有,但每次你调用原来的multiply 时,它都会在一个较小的列表中调用自己!
它将[ [1,3,6.7,7.0], [], [1,8.22,9,0] ] 与x : xs 模式匹配,从而产生x = [1,3,6.7,7.0] 和xs = [ [], [1,8.22,9,0] ]。然后它调用multiply xs。
所以在第二次调用中,我们将[ [], [1,8.22,9,0] ] 与x : xs 模式进行匹配。在本次评估中,x = [] 和 xs = [ [1,8.22,9,0] ]。我们用这个版本的xs 再次调用multiply xs。
现在在第三次调用中,我们将 [ [1,8.22,9,0] ] 与模式 x : xs 匹配。为了成功,我们必须找到 both x 和 xs。单个元素列表的尾部是空列表,所以x = [1,8.22,9,0] 但xs = []。然后我们用这个版本的xs 再次调用multply xs,这就是问题所在。现在我们尝试将[] 与x : xs 模式匹配,但我们不能,但也没有其他模式可以尝试,所以我们只得到Non-exhaustive patterns in function multiply。