我仍在努力探索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
但是,为什么<
和>
(以及扩展名=
,<=
和>=
)可以吗?
F#编译器对equality
和comparison
的处理方式有所不同(请参阅specs中的5.2.10相等性和比较约束,感谢@Daniel)。您将获得特殊 comparison
约束,该约束在以下情况下才允许使用(请参见规范以获取更多详细信息):
+
运算符没有这种特殊处理。为什么没有numeric
这样的约束?
难道不是也为字符串定义了该运算符吗?在某些语言中用于列表和集合?当然,这将是addable
约束,而不是numeric
。然后,可以在具有不同语义含义的程序中找到许多这样的重载运算符。因此,F#提供了具有静态成员约束和inline关键字的“包罗万象”方法。仅equality
和comparison
是特殊的。