使用 List.sum 时类型约束不匹配

Type constraint mismatch when using List.sum

我可能已经离开 F# 太久了,但我希望它能编译:

module Calc

let foo values = List.sum values

相反,我得到一个编译错误:

FS0071 Type constraint mismatch when applying the default type 'obj' for a type
inference variable. The type 'obj' does not support the operator '+' Consider
adding further type constraints

这也发生在 List.average 上,所以起初我认为它与通用约束有关,例如 requires member ( + ) 和 member get_Zero,但这不是全部,因为 let foo values = List.max values 编译(List.max 也有一个通用约束,尽管更简单 - 它只需要比较)。

我做错了什么?

这是一个 .NET 5.0 项目。在 Visual Studio 和 dotnet build.

中编译均失败

List.sum 有一个 SRTP 类型,要求列表的元素在其上定义了一个 (+) 运算符:

val sum:
   list: list< ^T>
      -> ^T (requires static member ( + ) and static member Zero )

当您在不知道列表元素类型的情况下尝试调用它时,编译器无法解析 SRTP。


一个选择 是标记 foo 本身 inline:

let inline foo values = List.sum values

这样,foo本身将继承SRTP要求:

val foo:
   values: list< ^a>
        -> ^a (requires static member ( + ) and static member Zero )

你只是把问题解决了 - 大概到了你知道元素类型的地步。

如果没有 inline 修饰符,这将不起作用,因为 SRTP 无法编译为 IL。


另一个选项,如果你负担得起的话,是指定一个元素类型,这样它就有一个(+)运算符:

let foo (values: int list) = List.sum values

这样编译器就可以通过观察 int 确实有一个 (+) 运算符来解析 SRTP。


这适用于 List.max,因为 max 没有 SRTP 约束。它只有一个 'T :> IComparison 约束,由 IL 支持,因此它们不必是 SRTP。