4

我在 F# 中试图创建一个类型参数必须支持添加的通用接口,所以我最终得到了这样的结果:

type IMyInterface<'b when 'b : (static member (+) : 'b * 'b -> 'b)> =
    abstract member myFunction : 'b -> 'b

不幸的是,这段代码给了我以下错误:

此代码不够通用。当 ^D : 比较和 ^D : (静态成员 ( + ) : ^D * ^D -> ^D) 时的类型变量 ^D 无法泛化,因为它会超出其范围。

我发现这个问题与同一问题有关,但我不确定我是否理解为什么必须将函数标记为inline.

另外,由于您不能创建一个抽象成员inline,是否存在我可以在我的具体示例中使用的另一种解决方案?还是我必须找到另一种方法来实现这一目标?

4

2 回答 2

8

首先,我想我不完全明白为什么你需要声明接口的类型参数支持加法-我想加法会在实现中使用MyFunction,在这种情况下,接口的调用者不需要知道关于它。如果要公开添加,可以简单地将其添加为单独的方法:

type IMyInterface<'T> =
  abstract Add : 'T * 'T -> 'T
  abstract MyFunction : 'T -> 'T

inline我认为静态成员约束在函数或静态成员之外的其他地方效果不佳inline(但我可能错了)。如果您需要在泛型类型中使用数字操作,您可以使用捕获实现(在inline方法中)并将它们存储在接口中的技巧。在我的博客末尾有一个关于 F# 中的通用数学的示例。

诀窍是使用您需要的数字操作定义一个接口,并将其作为附加参数传递给构造函数:

type IAddition<'T> =
  abstract Add : 'T * 'T -> 'T

type MyType<'T>(a:'T, b:'T, add:IAddition<'T>) =
  member x.Sum = add.Add(a, b)

到目前为止,这是以标准 .NET 方式使用接口 - 接口表示数字操作,我们通过接口调用它们。现在,诀窍是添加只接受两个参数并要求作为静态约束的inline方法。然后该方法可以实现接口并将其作为最后一个参数传递给:Create+MyType

  static member inline Create(a:^N, b:^N) =
    let ops = 
      { new IAddition< ^N > with
          member x.Add(a, b) = a + b }
    MyType< ^N >(a, b, ops)

现在您可以编写MyType<_>.Create(1, 2)并且+整数的操作将被自动捕获并存储在一个接口中(这在您的其余代码中更容易使用)。

于 2013-03-26T13:56:40.820 回答
2

MSDN 上的静态解析类型参数可能会阐明对inline. 底线是你不能把约束放在界面上,它也不是需要它的地方。(你真的想要一个接口“泄漏”相当于实现细节的东西吗?记住,这个约束只存在于编译时。)函数可能是inline,所以这是可行的:

type IMyInterface<'b> =
    abstract member myFunction : 'b -> 'b

// (^b : (static member (+) ...) constraint is inferred
let inline makeMyInterface() =
  { new IMyInterface<_> with
      member x.myFunction b = b + b }
于 2013-03-26T13:56:27.447 回答