MYV*_*MYV 7 haskell list empty-list
我在haskell中有以下zip函数的实现
myzip (a:b) (z:g)
| b == [] = []
| g == [] = []
| otherwise = (a,z) : myzip b g
Run Code Online (Sandbox Code Playgroud)
当我将其加载到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
Run Code Online (Sandbox Code Playgroud)
失败,模块加载:无.
我真的不确定为什么这不起作用.任何人都可以给我任何帮助吗?
Ben*_*Ben 14
实际上,你在问题中给出的函数编译得很好.如果你有的话,你会得到你引用的错误:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
| b == [] = []
| g == [] = []
| otherwise = (a, z) : myzip b g
Run Code Online (Sandbox Code Playgroud)
使用显式类型签名,说明myzip适用于任何类型a和列表b.但是,你已经使用b == []和g == [].等于运算符不是在任何类型上定义的,仅在类型类的成员类型上定义Eq,因此您编写的代码与您提供的类型不匹配.
这就是错误信息非常简单的说法,但是如果你刚刚学习并且尚未开始输入类,那么它有点不清楚.
如果您更改类型签名myzip以表示a并且b需要成为Eq类型类的成员,那么您提供的代码将起作用:
myzip :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)]
Run Code Online (Sandbox Code Playgroud)
或者,如果您完全不使用类型签名(正如您在问题中所做的那样),GHC实际上会从您使用==运算符的事实中推断出这种类型,并且代码只是按原样编译.
然而,检查列表是否为空可以不使用来完成==操作,所以你可以写myzip,这样它确实对任何类型的工作a和b.一种方法是使用该null功能:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
| null b = []
| null g = []
| otherwise = (a, z) : myzip b g
Run Code Online (Sandbox Code Playgroud)
但更常见的方法是简单地使用多个方程来定义myzip,基本案例与模式匹配,[]并且主要案例可以假设列表是非空的:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:[]) _ = []
myzip _ (z:[]) = []
myzip (a:b) (z:g) = (a, z) : myzip b g
Run Code Online (Sandbox Code Playgroud)
请注意,此样式也明显表明您的实现存在错误.你扔掉了最后一个a或者z,并且没有任何情况下列表完全是空的!
当你的等式说myzip (a:b) (z:g),然后检查b并g反对空列表,它实际上是太晚检查错误的事情.你并不需要检查,如果b是[],则需要检查是否完整列表是空的.但是你已经假设它不是空的并且将它分解成了a:b.这导致你的代码(a)返回错误的结果,因为它丢弃它应该压缩的最后一对元素,以及(b)当其中一个参数是空列表时产生错误.
列表上的递归通常看起来更像这样:
myzip :: [a] -> [b] -> [(a, b)]
myzip [] _ = []
myzip _ [] = []
myzip (a:b) (z:g) = (a, z) : myzip b g
Run Code Online (Sandbox Code Playgroud)
这行为正确.