为什么算术运算符的参数类型默认为int? [英] Why does the argument type of arithmetic operators default to int?

查看:159
本文介绍了为什么算术运算符的参数类型默认为int?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

但是为什么实际上是必要的吗?为什么不仅仅推断类型为'a -> 'a -> 'a还是类似的东西?似乎可以进行比较:g x y = x < y的类型是x:'a -> y:'a -> bool when 'a : comparison.为什么还不算术运算符呢?

编译器不能从调用站点静态推断特定的原始类型,并从那里专门化泛型函数,如果失败的话,又回落到一些动态调度上?

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

解决方案

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

let inline f x y = x + y

但是请注意,签名是:

x: ^a -> y: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

这是因为在.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)

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

比较是另一回事,因为该约束实际上存在于.NET级别,因此可以在IL中对其进行编译和编码,而成员约束则需要在编译时进行解析,这就是为什么该功能必须标记为内联的原因. /p>

我认为您对链接问题中的解释有误解:这不是由于性能折衷,真正的原因是.NET类型系统的限制.内联函数在大多数情况下执行速度更快(因为它已由编译器内联),这是次要的作用.

I am new to F#, and I was surprised to find that the type of f x y = x + y is actually int -> int -> int. Appearently, this is due to some performance trade-off.

But why is this actually necessary? Why not just infer the type to be 'a -> 'a -> 'a or something similar? It seems to work for comparison: the type of g x y = x < y is x:'a -> y:'a -> bool when 'a : comparison. Why not for arithmetic operators as well?

Couldn't the compiler statically infer the specific primitive types from the call sites and specialize the generic function from there, falling back to some dynamic dispatch if this fails?

This might very well be obvious, but I could not find any good resources on this. What is the reasoning behind this behavior?

解决方案

Yes, for those operators int is the default type inferred unless you specify a different one or is inferred by the use. If you want to define them for all types you have to make the function inline:

let inline f x y = x + y

But notice that the signature is:

x: ^a -> y: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

This is because in .NET you can't use member constraints but F# resolves them at compile time. That's why you see those 'hat types' and the constraint that those type should have a static member (+) defined.

Also notice the type variables are not a -> a -> a as you suggest, that's because in the .NET framework not all addition operations respect that signature. Things are different in other environments like Haskell, there the addition is strictly a -> a -> a but in .NET you can add for instance a TimeSpan to a DateTime:

System.DateTime(2000,1,1) + new System.TimeSpan(1, 2, 0, 30, 0)

and the result it's a DateTime, here the signature is: a -> b -> a

Comparison is a different story since that constraint actually exists at .NET level so it can be compiled and encoded in the IL whereas member constraints need to be resolved at compile time, that why the function has to be marked as inline.

I think you misinterpreted the explanation in the linked question: this is not due a performance trade-off, the real reason is a .NET type system limitation. The fact that an inline function executes faster in most cases (since it's inlined by the compiler) is a secondary effect.

这篇关于为什么算术运算符的参数类型默认为int?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆