我在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
失败,模块加载:无。
我真的不确定为什么这不起作用。任何人都可以给我任何帮助吗?
答案 0 :(得分:14)
实际上你在问题中给出的功能编译得很好。如果您拥有的是,将收到您引用的错误:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
| b == [] = []
| g == [] = []
| otherwise = (a, z) : myzip b g
使用明确的类型签名,表示myzip
适用于任何类型a
和b
的列表。但您已使用b == []
和g == []
。等于运算符不是在任何类型上定义,仅在作为Eq
类型类成员的类型上定义,因此您编写的代码与您给出的类型不匹配
这是错误消息非常简单的说法,但是如果你刚刚学习并且还没有开始输入类,那么它有点不清楚。
如果您更改myzip
的类型签名以表示a
和b
需要成为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
这种行为正确。