2009-10-07 35 views
2

我试图编译在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..]列表作为枚举类型,我怎么能解决这个问题。请记住,我想利用这里的懒惰评估,因此无限的名单。

+1

岂不'DIFF [] = []'或'的diff [_] = [0]'更好?毕竟,x^2 + 1的第四个微分应该是一个常数0,而不是一个错误。 – ephemient 2009-10-07 19:41:46

+0

@ephemient:你是鹰眼!我在发布问题后处理单例列表异常。该代码还应该读取'[1 ..]'而不是'[0 ..]'来区分它。 – Zaid 2009-10-07 19:50:58

回答

8

[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..]) 
+2

嗯,我可能会写'(迭代(+1),0)',因为它是短,但最终它都一样... – ephemient 2009-10-07 19:38:47

+1

有趣。我认为这只是一个无限的整数列表。你学到的东西... – Zaid 2009-10-07 19:39:33

+0

有趣的是,整个问题可以通过简单地省略类型签名并让推理机完成它的工作来解决。 – Dario 2009-10-07 19:52:29

7

正确类型的diff必须是

diff :: (Num a, Enum a) => [a] -> [a] 

因为[x..]的使用需要来实例化Enum类型。

2

下面是编译器在看这个函数时看到的内容的一个快速总结:

  • [0 ..]是同时包含Num和Enum实例的事物的列表。它是因为“0”民,并且它必须是因为一个枚举“..”
  • 我被要求申请(*),以_系数和[0的元素.. ]一个接一个。由于(*)的参数必须是相同的类型,并且[0 ..]具有Enum实例,coeff还必须具有Enum实例。
  • 错误! diff的类型签名只提到coeff有一个Num实例,但我已经确定它至少也必须有一个Enum实例。
+0

这解释了为什么另一个函数没有抛出这个错误。该函数涉及一个简单的'zip':'(a,b)< - zip coeff [0 ..]'返回可能有混合数据类型的元组。 – Zaid 2009-10-07 19:59:53

相关问题