我仍在努力探索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的情况下,可以通过声明内联函数来避免问题,这使它获得了通用类型定义,即
'a * 'b -> 'c (requires member (+))
,但这并不能解释为什么在这种情况下需要这样做,而不是另一个。
最佳答案
@TomasP在这里就此问题撰写了出色的文章:http://tomasp.net/blog/fsharp-generic-numeric.aspx
When writing simple generic code that has some type parameter 'T, we don’t know anything about the type parameter and there is no way to restrict it to a numeric type that provides all the operators that we may need to use in our code. This is a limitation of the .NET runtime and F# provides two ways for overcoming it.
但是,为什么
<
和>
(以及扩展名=
,<=
和>=
)可以吗?F#编译器对
equality
和comparison
的处理方式有所不同(请参阅specs中的5.2.10相等性和比较约束,感谢@Daniel)。您将获得特殊 comparison
约束,该约束在以下情况下才允许使用(请参见规范以获取更多详细信息):If the type is a named type, then the type definition does not have, and is not inferred to have, the NoComparison attribute, and the type definition implements System.IComparable or is an array type or is System.IntPtr or is System.UIntPtr.
+
运算符没有这种特殊处理。为什么没有numeric
这样的约束?难道不是也为字符串定义了该运算符吗?在某些语言中用于列表和集合?当然,这将是
addable
约束,而不是numeric
。然后,可以在具有不同语义含义的程序中找到许多这样的重载运算符。因此,F#提供了具有静态成员约束和inline关键字的“包罗万象”方法。仅equality
和comparison
是特殊的。
关于generics - F#中的泛型函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10589729/