假设我有一个支持给定成员函数的类型族,比如下面的Property成员:
type FooA = {...} with
member this.Property = ...
type FooB = {...} with
member this.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#中实现等价的实现?
发布于 2010-09-02 07:32:08
在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 (或者实际上搜索".NET generics C++ templates“时出现的任何内容)。
发布于 2010-09-02 08:04:50
我认为在这种情况下(即使在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实现某些指定的接口,但这里不需要这样做,因为在编写sum f1 f2时,F#会自动将参数从类型(如FooA )转换为接口。
使用不可变的接口和类型通常在F#中很有意义。对于你的问题,可能有一个“更实用”的解决方案,但这需要更多的上下文。
发布于 2010-09-02 10:47:19
C++模板大致使用一种“结构静态子类型”关系(有点像“鸭子类型”),而.NET泛型使用名义子类型。正如@kvb所说,您可以在F#中使用inline和静态成员约束来模拟C++的东西,但这样做时要非常小心。还有一些其他方法可以表达类似的关系;@Tomas展示了一种方法(OO子类型),另一种方法是传递方法字典(它知道如何从一组固定的类型中投影出.Property )。(如果这是Haskell,您可以使用类型类。)
https://stackoverflow.com/questions/3622750
复制相似问题