F#中的加法类型(+)

时间:2011-06-08 21:26:04

标签: types f# ocaml inline

我刚刚了解到OCAML必须有一个.后缀来进行浮点运算。一个例子是3. +. 4.,它等于7.(浮点数)。但是,F#以相同的方式处理float和integer算术,因此3 + 4(int)和3. + 4.(float)都可以工作。

F#自然地将+分配给int,因此let add a b = a + b的类型为int -> int -> int。确实(+)给了我val it : (int -> int -> int) = <fun:it@6-1>

这导致了以下序列,我认为这非常违反直觉:

> 3. + 4.;;
val it : float = 7.0
> (+);;
val it : (int -> int -> int) = <fun:it@8-2>

所以我的问题是:编译器中的特殊机制/案例是否完成了“重载”,或​​者这是一个语言范围的事情,所以我可能会定义一个名为{{1}的函数(或其他任何东西),它有一个整数定义,一个浮点数(或任何其他类型。)

3 个答案:

答案 0 :(得分:12)

简而言之,F#通过inline关键字和“静态成员约束”具有ad-hoc重载机制。内置数学运算符还有一些特殊的魔法,它神奇地假设类型int没有其他约束。 (+)只是所有F#中最特殊/最神奇的东西,因此它不能很好地介绍语言/类型系统。

通常,对于静态类型的类型推断语言来说,“重载”很困难。 F#在这里的选择非常务实。 OCaml做了一个不同的,简单的,实用的东西(没有重载)。 Haskell做了一个不同的,复杂但优雅的东西(类型类)。它们在语言/图书馆设计领域都是有点合理的。

答案 1 :(得分:6)

重载函数(和运算符)必须在F#中标记为inline。这是因为它们依赖于explicit member constraints。这些约束在编译时解决。函数let inline add a b = a + b的类型为'a -> 'b -> 'c (requires member (+)),其中+是静态函数/运算符。你不能在C#中做到这一点;它没有静态成员约束。

let inline add a b = a + b
add 1 2 //works
add 1.0 2.0 //also works

答案 2 :(得分:3)

除了Brian的回答和链接:

https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs

我在代码中找到了一些定义:

let inline (+) (x:int) (y:int) = (# "add" x y : int #)

let inline (+) (x: ^T) (y: ^U) : ^V = 
     AdditionDynamic<(^T),(^U),(^V)>  x y 
     when ^T : int32       and ^U : int32      = (# "add" x y : int32 #)
     when ^T : float       and ^U : float      = (# "add" x y : float #)
     when ^T : float32     and ^U : float32    = (# "add" x y : float32 #)
     ...

此处定义了AdditionDynamic(静态内容和CIL的加载): https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs#L2374

有趣的东西:

(# "add" 1 2 : int32 #)

工作,并输出3作为输出(警告说你不应该这样做。)