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

vla*_*fau 4 haskell

我正在编写一个程序,它接受一个元素列表(这样的列表必须采用整数和小数)并给出一个减少的总和列表:

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

到目前为止我的结果是:

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]
Run Code Online (Sandbox Code Playgroud)

我收到错误:

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

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

bhe*_*ilr 11

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

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: res)
Run Code Online (Sandbox Code Playgroud)

这相当于

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: b)
Run Code Online (Sandbox Code Playgroud)

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

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

ERROR "task9-02-1.hs":5 - Inferred type is not general enough
Run Code Online (Sandbox Code Playgroud)

推断类型不够通用,因为推断类型具有Num约束.

在GHC中,你会得到错误

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)’
Run Code Online (Sandbox Code Playgroud)

对我来说,这个人是一个更加清楚一点,因为它提到的"类型的变量res在第二线",并说,它预计它具有[res]同时期望的类型[t],其中cuttingSum_iter有型[t] -> [a] -> [a].看到它提到"类型变量res"和"预期类型:[res]",这至少指出了问题的原因,尽管仍然不能立即清楚实际上是什么问题.