为什么Haskell将我的Num类型解释为Enum?
问题描述:
我试图编译在Haskell下面的函数来模仿多项式,其常数的数值列表中指定的分化:为什么Haskell将我的Num类型解释为Enum?
diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) [0..]
哈斯克尔拒绝编译它,给我的理由如下:
Could not deduce (Enum a) from the context (Num a)
arising from the arithmetic sequence `0 .. ' at fp1.hs:7:38-42
Possible fix:
add (Enum a) to the context of the type signature for `diff'
In the third argument of `zipWith', namely `[0 .. ]'
In the expression: zipWith (*) (tail coeff) ([0 .. ])
In the definition of `diff':
diff coeff = zipWith (*) (tail coeff) ([0 .. ])
为什么Haskell的治疗[0..]
列表作为枚举类型,我怎么能解决这个问题。请记住,我想利用这里的懒惰评估,因此无限的名单。
答
[0..]
简写为enumFrom 0
语法糖,在Enum
类中定义。因为你想[0..]
产生的a
个列表中的编译器要求a
是在Enum
类。
您可以通过生成[0..] :: [Integer]
和使用fromInteger
(在Num
类中定义)的Enum a
添加到它周围的功能或工作类型签名,以得到一个[a]
:
diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) (map fromInteger [0..])
答
正确类型的diff
必须是
diff :: (Num a, Enum a) => [a] -> [a]
因为[x..]
的使用需要来实例化Enum
类型。
答
下面是编译器在看这个函数时看到的内容的一个快速总结:
- [0 ..]是同时包含Num和Enum实例的事物的列表。它是因为“0”民,并且它必须是因为一个枚举“..”
- 我被要求申请(*),以_系数和[0的元素.. ]一个接一个。由于(*)的参数必须是相同的类型,并且[0 ..]具有Enum实例,coeff还必须具有Enum实例。
- 错误! diff的类型签名只提到coeff有一个Num实例,但我已经确定它至少也必须有一个Enum实例。
+0
这解释了为什么另一个函数没有抛出这个错误。该函数涉及一个简单的'zip':'(a,b) Zaid 2009-10-07 19:59:53
岂不'DIFF [] = []'或'的diff [_] = [0]'更好?毕竟,x^2 + 1的第四个微分应该是一个常数0,而不是一个错误。 – ephemient 2009-10-07 19:41:46
@ephemient:你是鹰眼!我在发布问题后处理单例列表异常。该代码还应该读取'[1 ..]'而不是'[0 ..]'来区分它。 – Zaid 2009-10-07 19:50:58