haskell执行“zip”奇怪的错误

时间:2013-05-05 04:17:03

标签: list haskell empty-list

我在haskell中有以下zip函数的实现

myzip (a:b) (z:g)
    | b == [] = []
    | g == [] = []
    | otherwise = (a,z) : myzip b g

当我将其加载到ghci时,我收到以下错误

No instance for (Eq b)
  arising from a use of `=='
In the expression: g == []
In a stmt of a pattern guard for
               an equation for `myzip':
  g == []
In an equation for `myzip':
    myzip (a : b) (z : g)
      | b == [] = []
      | g == [] = []
      | otherwise = (a, z) : myzip b g

失败,模块加载:无。

我真的不确定为什么这不起作用。任何人都可以给我任何帮助吗?

1 个答案:

答案 0 :(得分:14)

实际上你在问题中给出的功能编译得很好。如果您拥有的是收到您引用的错误:

myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
    | b == [] = []
    | g == [] = []
    | otherwise = (a, z) : myzip b g

使用明确的类型签名,表示myzip适用于任何类型ab的列表。但您已使用b == []g == []。等于运算符不是在任何类型上定义,仅在作为Eq类型类成员的类型上定义,因此您编写的代码与您给出的类型不匹配

这是错误消息非常简单的说法,但是如果你刚刚学习并且还没有开始输入类,那么它有点不清楚。

如果您更改myzip的类型签名以表示ab需要成为Eq类型类的成员,那么您提供的代码将有效:

myzip :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)]

或者如果你完全取消类型签名(正如你在问题中所做的那样),GHC实际上是从你使用==运算符的事实推断出这种类型,而代码只是按原样编译。 / p>

但是,可以在不使用==运算符的情况下检查列表是否为空,因此您可以编写myzip以便它确实可以对任何类型a和{{进行操作1}}。一种方法是使用b函数:

null

但更常见的方法是简单地使用多个方程来定义myzip :: [a] -> [b] -> [(a, b)] myzip (a:b) (z:g) | null b = [] | null g = [] | otherwise = (a, z) : myzip b g ,基本情况与模式myzip匹配,并且主要情况可以假设列表是非空的:

[]

请注意,此样式也明显表明您的实现存在错误。你丢弃了最后的myzip :: [a] -> [b] -> [(a, b)] myzip (a:[]) _ = [] myzip _ (z:[]) = [] myzip (a:b) (z:g) = (a, z) : myzip b g a,并且列表完全没空的情况也没有了!

当你的等式表示z然后对空列表检查myzip (a:b) (z:g)b时,它实际上检查错误的事情为时已晚。您无需检查g是否为b,您需要检查整个列表是否为空。但是你已经假设它不是空的并且将它分解为[]。这导致你的代码(a)返回错误的结果,因为它丢弃它应该压缩的最后一对元素,以及(b)当其中一个参数是空列表时产生错误。

列表上的递归通常看起来更像这样:

a:b

这种行为正确。