F#是否具有通用算术支持?

时间:2010-02-09 00:38:41

标签: generics math f# inline

F#是否与C#有同样的问题,你不能直接使用泛型T类型的算术运算符?

你能编写一个通用的Sum函数来返回支持算术加法的任何值的总和吗?

4 个答案:

答案 0 :(得分:8)

正如brian所提到的,有一些对泛型算术的内置支持,你可以使用'静态约束',它允许你自己定义一些泛型函数(虽然这有点限制)。

除此之外,您还可以使用动态“数字关联”,在函数中使用时速度稍慢,但它可以很好地用于定义您自己的向量或矩阵类型。这是一个例子:

#r "FSharp.PowerPack.dll"
open Microsoft.FSharp.Math

let twoTimesLarger (n:'a) (m:'a) = 
  let ops = GlobalAssociations.GetNumericAssociation<'a>()
  let sel = if ops.Compare(n, m) > 0 then n else m
  ops.Multiply(sel, ops.Add(ops.One, ops.One))

我们首先需要引用包含该功能的F#PowerPack库。然后我们定义一个带有签名'a -> 'a -> 'a的泛型函数。第一行动态获取数值操作以使用类型'a(它实际上使用一些查找表,类型为键)。然后,您可以使用数字操作对象的方法来执行乘法,加法(MultiplyAdd)等许多其他操作。该功能适用​​于任何数字:

twoTimesLarger 3 4  
twoTimesLarger 2.3 2.4
twoTimesLarger "a" "b" // Throws an exception!

定义自己的数字类型时,可以定义其数值运算并使用GlobalAssociations.RegisterNumericAssociation进行注册。我相信这也意味着您可以在注册操作后使用内置的F#Matrix<YourType>Vector<YourType>

答案 1 :(得分:4)

F#对此有一些有限的支持。一个好的通用解决方案可能涉及类型类,一般不支持CLR,特别是F#。

F#使用“静态成员约束”和“内联”函数重载算术运算符。这是启用例如+运算符可以同时处理intfloat。您可以编写inline函数,这些函数的实现基于内置的数学运算符并取得一些进展,但总的来说这是非常重要的。您可以查看,例如源代码到Array.sum(在FSharp.Core中的array.fs中)与FTP一起出现的F#源代码分发中。

另请参阅此答案的“静态成员约束”和“模拟类型类”部分:

Functions with generic parameter types

以及像

这样的库的各个部分

http://msdn.microsoft.com/en-us/library/ee370581(VS.100).aspx

http://msdn.microsoft.com/en-us/library/ee340262(VS.100).aspx

答案 2 :(得分:4)

你可以这样做。

let inline sum<'a when 'a : (static member (+) : 'a -> 'a -> 'a)> a b =
    a + b

let result = sum<int> 3 4

但是,如果我尝试let result = sum 3 4,我会收到错误"type ambiguity inherent in the use of the operator '( + )'"

答案 3 :(得分:2)

我所知道的执行泛型算法的最佳机制是类型类,遗憾的是C#,F#和.Net运行时都不支持。但是,您可以手动模拟它们,如本博客文章中所述:

Type Classes Are The Secret Sauce

该技术应该在C#2.0或更高版本中使用(使用匿名委托/ lambdas)。

通常人们会转向界面,但会遇到一些问题

  1. 您不能声明现有类型实现接口,因此您无法为内置类型(如int)定义该接口的实例。
  2. 接口不能约束方法的其他参数的类型。
  3. 接口声明,对于所有实现,该接口上的所有方法都采用相同的隐式“this”参数类型。如果Foo实现了某个接口,那么显然'this'参数必须是该实现的Foo类型。但是没有办法要求其他方法参数属于Foo类型。

    Type classes允许您(除其他外)对所有方法参数执行此类约束,而不仅仅是第一个参数。

    正如前面引用的文章所述,您可以通过将函数表作为显式参数传递来模拟类型类。

    (社区维基:会在这篇文章中发布一个例子,这篇文章被翻译成C#,但是时间冗长,解释很久)