我有这个界面:
type IMovingFunc< 'T > =
abstract member Add : 'T -> unit
现在我想创建一个实现Add函数并使用(+)运算符的泛型类型:
type MovingSum< ^T >(initial : ^T) =
let mutable sum = initial
interface IMovingFunc< ^T> with
member inline this.Add x = sum <- sum + x
不幸的是,我收到了这个错误:
此代码不够通用。 ^ T时的类型变量^ T :(静态成员(+):^ T * ^ T - &gt; ^ T)无法推广,因为它会逃避其范围。
我尝试向MovingSum添加类型约束,但它没有帮助:
type MovingSum< ^T when ^T : (static member ( + ) : ^T * ^T -> ^T)>(initial : ^T)
你能告诉我如何解决这个问题,还是有其他办法来解决这个问题?
答案 0 :(得分:5)
托马斯的回答很好。但是,为了完整性: 可以在类型上使用静态解析的类型参数:
type MovingSum< ^T when ^T : (static member (+) : ^T * ^T -> ^T)>(initial : ^T) =
let mutable sum = initial
member inline this.Add(x:^T) = sum <- sum + x
let m = MovingSum(1) in m.Add(3) // works!
但请注意:
答案 1 :(得分:4)
正如Fyodor在评论中所提到的,类型不能以与函数相同的方式具有静态解析约束(主要是因为使用内联处理静态约束 - 并且您无法真正内联整个类型)。
解决此问题的一种方法是在类型中使约束显式化,然后使用静态成员约束创建一个捕获功能并将其传递给类型的函数。
在您的示例中,您需要+
运算符,因此我们可以添加adder
作为类型的参数:
type MovingSum<'T>(initial:'T, adder:'T -> 'T -> 'T) =
let mutable sum = initial
interface IMovingFunc<'T> with
member this.Add x = sum <- adder sum x
这不需要静态成员约束,但您需要在创建MovingSum
时提供额外参数。这不是太糟糕,但您可以通过定义创建MovingSum
并捕获+
运算符的内联函数来避免这种情况:
let inline movingSum initial =
MovingSum(initial, fun a b -> a + b) :> IMovingFunc<_>