【问题标题】:Haskell Beginner, recursive function, list, Error: Non-exhaustive patternsHaskell 初学者,递归函数,列表,错误:非穷举模式
【发布时间】:2018-10-09 13:02:15
【问题描述】:

我尝试编写一个函数 [int] -> int 用迭代函数计算整数列表的总和(结果应该等于内置函数 sum)

19>sumList :: [Int] -> Int
20>sumList [list] | length[list] > 0  = [list]!!0 + sumList (drop 1 [list])
21>               | otherwise = 0

这是我尝试运行的结果

uebung1.lhs:20:2: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘sumList’:
    Patterns not matched:
        []
        (_:_:_)
Ok, modules loaded: Main.
*Main> sumList []
*** Exception: uebung1.lhs:(20,2)-(21,31): Non-exhaustive patterns in     function sumList

*Main> sumList [3]
*** Exception: uebung1.lhs:(20,2)-(21,31): Non-exhaustive patterns in   function sumListi i i i i 

我做错了什么?我已经睡了一个晚上,但我只是不明白问题出在哪里。受保护的方程应该捕获所有列表长度的情况。感谢您的建议。

【问题讨论】:

  • 这不是递归的吗?
  • 是的,确实修复了它

标签: list haskell recursion


【解决方案1】:

其他人已经回答了,但我想强调编译器发出的警告发现了问题:

Pattern match(es) are non-exhaustive
In an equation for ‘sumList’:
    Patterns not matched:
        []
        (_:_:_)

这是说代码在其模式匹配中没有处理某些情况。上面的空列表[]被报告为不匹配,意味着程序会在空列表上崩溃。此外,(_:_:_) 形式的列表不匹配:这些列表具有至少两个元素,例如 1:2:rest,它是一个以元素 12 开头的列表,然后是列表 rest用于下一个元素。

所以,警告告诉我们我们只处理长度为 1 的列表。实际上,我们只处理[_] 模式,这与_:[] 相同——从一个元素开始然后到那里结束的列表。

如果你是初学者,我想你还没有学过模式匹配。这应该是你学习 Haskell 的首要任务:它是最重要的特性之一。一般来说,如果你的递归代码使用length, !!, tail, head,你很可能做错了。有些地方需要这些函数,但在许多简单的练习中它们不是,模式匹配通常足够且优雅。

【讨论】:

    【解决方案2】:

    该功能不适用于空列表或任何包含多个项目的列表。

    您的问题是您正在匹配[list],这是一个包含一个成员list 的列表。相反,请尝试仅匹配 list。这意味着它将匹配来自您的类型签名的 [Int] 类型的任何内容。

    我明白你的困惑,因为 [a] 类型适用于任何长度的列表,但 [a] 只会匹配一个元素的列表。

    我还附上了另一种使用模式匹配编写函数的方法,希望对你有用。

    sumList :: [Int] -> Int
    sumList [] = 0
    sumList (x:xs) = x + sumList xs
    

    使用守卫是不寻常的,但你这样做了,你的代码看起来像这样:

    sumList :: [Int] -> Int
    sumList list
        | length list > 0 = head list + sumList (tail list)
        | otherwise = 0
    

    注意[list] 已被list 替换,!! 0 已被head 替换,drop 1 已被tail 替换。

    Hoogle 是你的朋友!

    您还可以将空列表的检查移至第一个守卫,如下所示:

    sumList :: [Int] -> Int
    sumList list
        | list == [] = 0
        | otherwise = head list + sumList (tail list)
    

    请注意此代码与模式匹配代码的相似程度。

    【讨论】:

      【解决方案3】:

      问题是你的模式只匹配一个包含一个元素的列表。

      例如,如果您尝试在ghci 中定义一个函数:

      a [x] = x
      

      然后尝试使用具有不同数量元素的列表来调用它:

      a [1] 结果为1

      a [] 结果为Exception: <interactive>:5:1-13: Non-exhaustive patterns in function a

      a [1,2] 结果为Exception: <interactive>:1:1-9: Non-exhaustive patterns in function a

      以下修改使您的功能正常工作:

      sumList :: [Int] -> Int
      sumList list | length list > 0  = list!!0 + sumList (drop 1 list)
                   | otherwise = 0
      

      但是,当然,以下定义会更惯用和更有效:

      sumList :: [Int] -> Int
      sumList [] = 0
      sumList (x:xs) = x + sumList xs
      

      通过(x:xs) 模式,您会立即收到x 作为列表头(list!!0)和xs 作为列表尾(drop 1 list

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多