为什么算术运算符的参数类型默认为int?

use*_*730 6 f#

我是F#的新手,我很惊讶地发现它的类型f x y = x + y实际上是int -> int -> int.显然,这是由于一些性能权衡.

为什么这实际上是必要的呢?为什么不直接推断类型'a -> 'a -> 'a或类似的类型?它似乎可以用于比较:类型g x y = x < yx:'a -> y:'a -> bool when 'a : comparison.为什么不对算术运算符呢?

编译器无法从调用站点静态推断出特定的基本类型,并从那里专门化泛型函数,如果失败则回退到某些动态调度?

这可能很明显,但我找不到任何好的资源.这种行为背后的原因是什么?

Gus*_*Gus 10

是的,对于那些运算符int是推断的默认类型,除非您指定不同的或由使用推断.如果要为所有类型定义它们,则必须使函数内联:

let inline f x y = x + y
Run Code Online (Sandbox Code Playgroud)

但请注意签名是:

x: ^a -> y: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)
Run Code Online (Sandbox Code Playgroud)

这是因为在.NET中您不能使用成员约束,但F#在编译时解析它们.这就是为什么你会看到那些"帽子类型"以及那些类型应该定义静态成员(+)的约束.

另请注意,类型变量并不a -> a -> a像您建议的那样,因为在.NET框架中并非所有添加操作都遵循该签名.在像Haskell这样的其他环境中,情况有所不同,严格要求a -> a -> a添加,但在.NET中,您可以将TimeSpan添加到DateTime:

System.DateTime(2000,1,1) + new System.TimeSpan(1, 2, 0, 30, 0)
Run Code Online (Sandbox Code Playgroud)

结果是DateTime,这里的签名是: a -> b -> a

比较是一个不同的故事,因为该约束实际上存在于.NET级别,因此它可以在IL中编译和编码,而成员约束需要在编译时解决,这就是为什么函数必须标记为内联.

我认为你误解了链接问题中的解释:这不是由于性能权衡,真正的原因是.NET类型的系统限制.内联函数在大多数情况下执行得更快(因为它由编译器内联)这一事实是次要影响.