向派生类型 F# 添加类型约束(此代码不够通用)
Add type constraint to derived type F# (This code is not sufficiently generic)
我有这个界面:
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
不幸的是,我收到了这个错误:
This code is not sufficiently generic. The type variable ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) could not be generalized because it would escape its scope.
我试过向 MovingSum 添加类型约束,但没有帮助:
type MovingSum< ^T when ^T : (static member ( + ) : ^T * ^T -> ^T)>(initial : ^T)
能否请您告诉我如何解决这个问题,或者有其他方法可以解决这个问题吗?
正如 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<_>
Tomas 的回答很好。但是,为了完整性: 可以在类型上使用静态解析的类型参数:
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!
但请注意:
- 需要在声明参数的地方包含成员约束。
- 我在这里收到了一些虚假警告,表明此语言功能可能尚未完全成熟...
- 无论如何这对你没有帮助,因为接口成员不能被内联 - 给定一个接口类型的值,编译器没有任何方法来确定实现接口的运行时类型,所以不可能知道要内联什么实现。
我有这个界面:
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
不幸的是,我收到了这个错误:
This code is not sufficiently generic. The type variable ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) could not be generalized because it would escape its scope.
我试过向 MovingSum 添加类型约束,但没有帮助:
type MovingSum< ^T when ^T : (static member ( + ) : ^T * ^T -> ^T)>(initial : ^T)
能否请您告诉我如何解决这个问题,或者有其他方法可以解决这个问题吗?
正如 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<_>
Tomas 的回答很好。但是,为了完整性: 可以在类型上使用静态解析的类型参数:
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!
但请注意:
- 需要在声明参数的地方包含成员约束。
- 我在这里收到了一些虚假警告,表明此语言功能可能尚未完全成熟...
- 无论如何这对你没有帮助,因为接口成员不能被内联 - 给定一个接口类型的值,编译器没有任何方法来确定实现接口的运行时类型,所以不可能知道要内联什么实现。