繁体   English   中英

F#中的通用函数

[英]Generic functions in F#

我仍然试图围绕F#如何概括(或不是)函数和类型,并且有一个案例让我烦恼:

let min(a, b) = if a < b then a else b

let add(a, b) = a + b

let minInt = min(3, 4)
let minFloat = min(3.0, 4.0) // works!

let addInt = add(3, 5)
let addFloat = add(3.0, 5.0) // error: This expression was expected to have type
                             // int but here has type float

这里min有通用类型'a * 'a -> 'a (requires comparison)而add有一个具体类型int * int -> int ,显然是从它在程序中的第一次使用推断出来的。 两者都以相同的方式声明和使用,那为什么泛化的区别呢?

我理解在add的情况下,通过声明函数inline来解决问题,这会导致它获得泛型类型定义,即'a * 'b -> 'c (requires member (+)) ,但这并不能解释为什么在这种情况下需要这种情况而不是另一种情况。

@TomasP在这个问题上有一篇很好的文章: http ://tomasp.net/blog/fsharp-generic-numeric.aspx

在编写具有某个类型参数'T的简单通用代码时,我们对类型参数一无所知,并且无法将其限制为提供我们可能需要在代码中使用的所有运算符的数字类型。 这是.NET运行时的限制,F#提供了两种克服它的方法。

但为什么<> (以及扩展, =<=>= )好吗?

F#编译器以不同的方式处理equalitycomparison (请参阅规范中的5.2.10等式和比较约束,感谢@Daniel)。 你得到了特殊的 comparison约束,这是允许的(简单来说,请参阅规范了解更多细节):

如果类型是命名类型,那么类型定义没有,也没有推断出具有NoComparison属性,并且类型定义实现System.IComparable或者是数组类型或者是System.IntPtr或者是System.UIntPtr 。

+运算符没有这样的特殊处理。 为什么不能存在numeric等约束?

那不是那个也为字符串定义的运算符吗? 在某些语言中列表和集合? 当然它将是一个可addable约束而不是numeric 然后可以在具有不同语义含义的程序中找到许多这样的重载运算符。 所以F#提供了一个带有静态成员约束和inline关键字的'catch-all'方法。 只有equalitycomparison才是特殊的。

为何泛化的区别?

在一般性和表现之间存在权衡。 comparison约束为像min这样的函数提供了通用性,它可以对任何F#类型的任何值起作用,但在一般情况下它会转向虚拟分派并且慢很多倍。 +运算符提供有限的通用性,并且可以对任何已经过载增强但在一般情况下不起作用的F#类型的任何值起作用,因此总是非常快,因为永远不需要调度。

comparison是编译时约束。 所以问题仍然存在:为什么不add一般化? 正如yamen指出的那样,泛型数学操作需要内联,这会影响代码大小和性能 - 可能不是编译器应该自动执行的操作。

暂无
暂无

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

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