在Haskell中,推断类型不够通用

时间:2014-09-23 20:25:57

标签: haskell

我正在编写一个程序,它接受一个元素列表(这样的列表必须同时包含整数和小数)并给出 cut 总和的列表:

  • 结果列表的第一个元素是整个列表的总和
  • second是无头列表的总和
  • 第三个是没有头部和第二个元素的列表的总和
  • 等等。

到目前为止我的结果是:

cuttingSum :: Num a => [a] -> [a]
cuttingSum l = 
 let         
  cuttingSum_iter [] res = reverse (res)
  cuttingSum_iter ll res =
  cuttingSum_iter (tail ll) ((foldl (+) 0 ll) :: res)
 in
  cuttingSum_iter l []


main = do
 print $ cuttingSum [1,2,3]

我收到错误:

 ERROR "task9-02-1.hs":5 - Inferred type is not general enough
*** Expression    : foldl (+) 0 ll
*** Expected type : a
*** Inferred type : _26

我正在使用Hugs,因为它是任务要求,但ghci也显示出某种类似的错误。有什么问题?

1 个答案:

答案 0 :(得分:11)

问题只是一个错字,你有foldl (+) 0 ll :: res而不是foldl (+) 0 ll : res,只有一个:。这是因为::表示表达式的类型。当你有

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: res)

这相当于

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: b)

因为res作为参数而res作为一种类型存在于不同的名称空间中。在类型命名空间中,任何以小写字母开头的标识符都是类型变量,并且我们知道变量的名称对编译器无关紧要,只对程序员有意义。 从这一点开始,我会将其称为b,以避免与res参数混淆。

由于您告诉编译器表达式foldl (+) 0 ll具有类型b,因此它未通过类型检查阶段。编译器可以确定ll至少是一个列表,并且在foldl (+) 0中使用它意味着它必须包含Num个元素,因此foldl (+) 0 ll必须具有类型{{1 }}。这与类型Num a => a不匹配,因为b没有b约束。这就是导致您看到

的错误消息的原因
Num

推断类型不够通用,因为推断类型具有ERROR "task9-02-1.hs":5 - Inferred type is not general enough 约束。

在GHC中,你会得到错误

Num

对我来说,这个更清晰一点,因为它在第二行提到了“类型变量Couldn't match type ‘t’ with ‘res’ because type variable ‘res’ would escape its scope This (rigid, skolem) type variable is bound by an expression type signature: res at <interactive>:13:57-79 Expected type: [res] Actual type: [t] Relevant bindings include ll :: [t] (bound at <interactive>:13:21) cuttingSum_iter :: [t] -> [a] -> [a] (bound at <interactive>:12:5) In the third argument of ‘foldl’, namely ‘ll’ In the second argument of ‘cuttingSum_iter’, namely ‘((foldl (+) 0 ll) :: res)’ ”,并表示它期望res同时期望类型{{1其中[res]的类型为[t]。看到它提到“类型变量cuttingSum_iter”和“预期类型:[t] -> [a] -> [a]”,这至少指出了问题的原因,尽管仍然不能立即明确实际是什么问题

相关问题