为什么Haskell将我的Num类型解释为Enum?

时间:2009-10-07 19:13:03

标签: haskell type-inference typeclass

我正在尝试在Haskell中编译以下函数,以模仿在数值列表中指定常量的多项式的区分:

diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) [0..]

Haskell拒绝编译它,给出了以下原因:

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..]列表视为枚举类型,我该如何解决这个问题。请记住,我想利用这里的懒惰评估,因此无限列表。

4 个答案:

答案 0 :(得分:8)

[0..]enumFrom 0的语法糖,在类Enum中定义。由于您希望使用a生成[0..]的列表,因此编译器要求a位于类Enum中。

您可以将Enum a添加到该函数的类型签名中,也可以通过生成[0..] :: [Integer]并使用fromInteger(在类Num中定义)来解决该问题。 )从中得到[a]

diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) (map fromInteger [0..])

答案 1 :(得分:7)

diff的正确类型必须是

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

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

答案 2 :(得分:3)

[0..]enumFrom 0 See here

的简写

答案 3 :(得分:2)

以下是编译器在查看此函数时看到的内容的快速摘要:

  • [0 ..]是包含Num和Enum实例的事物列表。由于'0',它必须是一个Num,并且因为'..'而必须是一个Enum。
  • 我被要求逐一将(*)应用于coeff和[0 ..]的元素。由于(*)的两个参数必须是相同的类型,并且[0 ..]具有Enum的实例,因此coeff还必须具有Enum的实例。
  • 错误! diff的类型签名只提到coeff有一个Num实例,但我已经确定它至少也必须有一个Enum实例。