繁体   English   中英

F#通用编程 - 使用成员

[英]F# Generic Programming - Using members

假设我有一系列支持给定成员函数的类型,如下面的Property成员:

type FooA = {...} with

    member this.Property = ...

type FooB = {...} with

    member this.Property = ...

假设成员Property为上述每种类型返回一个整数。 现在,我想编写一个可以执行以下操作的通用函数:

let sum (a: 'T) (b: 'U) = a.Property + b.Property

我习惯用C ++编写以下代码:

template<typename T, typename U>
int sum(T a, U b)
{
    return a.Property + b.Property;
}

如何在F#中实现等效的实现?

可以在F#中执行此操作,但它不是惯用的:

let inline sum a b = (^T : (member Property : int) a) + (^U : (member Property : int) b)

一般来说,.NET泛型与C ++模板有很大不同,因此在尝试使用F#模拟C ++之前,可能首先要了解它们的差异。 一般的.NET哲学是操作由名义类型而不是结构类型定义。 在您的示例中,您可以定义一个公开Property属性的接口,您的两个类实现该属性,然后您的sum函数将接受该接口的实例。

有关F#泛型的更多信息,请参见http://msdn.microsoft.com/en-us/library/dd233215.aspx ; 有关.NET泛型与C ++模板的简要比较,请参阅http://blogs.msdn.com/b/branbray/archive/2003/11/19/51023.aspx (或者当您使用Google“.NET时出现的任何内容)泛型C ++模板“)。

我认为在这种情况下(即使在F#中)干净的方法是使用基本的面向对象编程并使用您需要的成员定义接口(例如Property ):

type IHasProperty =
  abstract Property : int

请注意,F#推断我们正在声明一个接口,因为它只有抽象成员而没有构造函数。 然后,您可以在类型中实现接口:

type FooA = {...} 
  interface IHasProperty with
    member this.Property = ... 

type FooB = {...} 
  interface IHasProperty with
    member this.Property = ... 

值得指出的是,任何F#类型(包括记录,有区别的联合,当然还有类)都可以实现接口。 现在,泛型函数可以只接受IHasProperty类型的两个参数:

let sum (a: IHasProperty) (b: IHasProperty) = a.Property + b.Property 

在这种情况下你甚至不需要泛型,但泛型也可以使用接口做一些技巧 - 你可以要求类型参数T来实现一些指定的接口,但这里不需要这样,因为F#会自动转换参数当你写sum f1 f2时,从FooA这样的类型到接口。

使用不可变的接口和类型在F#中通常是非常有意义的。 您的问题可能有一个“更实用”的解决方案,但这需要更多的上下文。

C ++模板大致使用一种“结构静态子类型”关系(有点像'鸭子打字'),而.NET泛型使用名义子类型。 正如@kvb所说,你可以在F#中使用inline和静态成员约束模拟C ++内容,但要非常谨慎。 还有一些其他方式来表达类似的关系; @Tomas显示一个(OO子类型),另一个是传递一个方法字典(它知道如何从一组固定的类型中突出.Property)。 (如果这是Haskell,你可以使用类型类。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM