F#是否与C#有同样的问题,你不能直接使用泛型T类型的算术运算符?
你能编写一个通用的Sum函数来返回支持算术加法的任何值的总和吗?
答案 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
(它实际上使用一些查找表,类型为键)。然后,您可以使用数字操作对象的方法来执行乘法,加法(Multiply
,Add
)等许多其他操作。该功能适用于任何数字:
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#使用“静态成员约束”和“内联”函数重载算术运算符。这是启用例如+
运算符可以同时处理int
和float
。您可以编写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)。
通常人们会转向界面,但会遇到一些问题
接口声明,对于所有实现,该接口上的所有方法都采用相同的隐式“this”参数类型。如果Foo实现了某个接口,那么显然'this'参数必须是该实现的Foo类型。但是没有办法要求其他方法参数也属于Foo类型。
Type classes允许您(除其他外)对所有方法参数执行此类约束,而不仅仅是第一个参数。
正如前面引用的文章所述,您可以通过将函数表作为显式参数传递来模拟类型类。
(社区维基:会在这篇文章中发布一个例子,这篇文章被翻译成C#,但是时间冗长,解释很久)