如何解决这个 Haskell 类型错误?预期类型和实际类型不匹配

How to solve this Haskell type error? Expected and actual types do not match

我正在尝试使用 foldr 和辅助函数将列表中的所有最大整数提取到另一个列表中。我对 foldr 的理解与错误消息有冲突。这是我的代码:

largest :: [Int] -> [Int]
largest [] = []
largest xs = foldr largestHelper [] xs

largestHelper :: [Int] -> Int -> [Int]
largestHelper [] prev = [prev]
largestHelper (lrg : lrgs) prev | lrg < prev  = [prev]
                                | lrg == prev = prev : (lrg : lrgs)  
                                | otherwise   = (lrg : lrgs)

对我来说,第一个要评估的函数似乎是 largestHelper,整数列表的最后一个元素和 []。接下来是 largestHelper 使用列表的倒数第二个元素和前一个迭代,它只是最后一个元素,因为它是迄今为止最大的。等等。所以最后 largest xs 计算出一个列表,其中包含一个或多个整数,其中最大值是从给定列表中找到的。

错误如下:

largest.hs:3:20: error:
    * Couldn't match type `[Int]' with `Int'
      Expected type: [Int] -> [Int] -> [Int]
        Actual type: [Int] -> Int -> [Int]
    * In the first argument of `foldr', namely `largestHelper'
      In the expression: foldr largestHelper [] xs
      In an equation for `largest':
          largest xs = foldr largestHelper [] xs
  |
3 | largest xs = foldr largestHelper [] xs
  |                    ^^^^^^^^^^^^^

largest.hs:3:37: error:
    * Couldn't match type `Int' with `[Int]'
      Expected type: [[Int]]
        Actual type: [Int]
    * In the third argument of `foldr', namely `xs'
      In the expression: foldr largestHelper [] xs
      In an equation for `largest':
          largest xs = foldr largestHelper [] xs
  |
3 | largest xs = foldr largestHelper [] xs
  |

第一个似乎说 largestHelper 实际上接收到两个整数列表,而不是它正在构造的列表。但是 foldr 不是一个一个地给出给 largest 的列表的元素,因此 largestHelper 的第二个参数确实是一个整数而不是整数列表吗? 第二个似乎说 largest 的参数实际上是 [[Int]] 而不是 [Int]。我不明白。

如果您能澄清这一困惑,我将不胜感激。我还不知道这是否有效,因为它不能编译,并且作为函数式编程的初学者 Haskell,考虑到代码的逻辑和风格,我也很感激。

您的两个类型错误遵循模式 Couldn't match type `foo' with `bar'Couldn't match type `bar' with `foo'。问题是 largestHelper 的参数顺序错误。 foldr 首先调用元素,然后调用累加器,但是 largestHelper 想要首先调用累加器,然后调用元素。调换它们的顺序,您的类型错误将得到修复。

让我们分解第一条错误信息:

largest.hs:3:20: error:
[...]
  |
3 | largest xs = foldr largestHelper [] xs
  |                    ^^^^^^^^^^^^^

编译器在您的文件 largest.hs 第 3 行第 20 列发现问题。它还打印了相关行。

* In the first argument of `foldr', namely `largestHelper'
  In the expression: foldr largestHelper [] xs
  In an equation for `largest':
      largest xs = foldr largestHelper [] xs

位置再次给出,但这次是根据参数、表达式和方程式给出的。我们得知 largestHelper.

有问题
* Couldn't match type `[Int]' with `Int'
  Expected type: [Int] -> [Int] -> [Int]
    Actual type: [Int] -> Int -> [Int]

编译器期望 largestHelper[Int] -> [Int] -> [Int] 类型,但发现它的实际类型是 [Int] -> Int -> [Int]。由于它们在 [Int]Int 方面不同,因此编译器报告了一个错误。

因此,在查看错误消息后,我们得出了两个新问题:

  • 为什么编译器期望 largestHelpler[Int] -> [Int] -> [Int] 类型?这是关于统一的问题,在 How to infer the type of an expression manually.
  • 上有一些很好的答案
  • 如何解决这个问题? .
  • 对此进行了解释

请注意,编译器能够识别问题是因为您的编程语言使用了类型。也就是说,类型赋予它发现代码有问题的能力。因此,编译器可能认为自己是您的有用伙伴,而实际上它会面对您最奇怪和最复杂的技术行话。由您来解决问题。