我刚刚了解到OCAML必须有一个 .
后缀用于执行浮点运算 . 一个例子是 3. +. 4.
,等于 7.
(浮动) . 但是,F#以相同的方式处理浮点和整数运算,因此 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>
所以我的问题是:"overloading"是由编译器中的特殊机制/案例完成的还是这是一个语言范围的事情所以我可能会定义一个名为 add
(或其他任何)的函数,它有一个整数定义和一个for浮子(或任何其他类型 . )
3 回答
简而言之,F#通过
inline
关键字和"static member constraints"具有ad-hoc重载机制 . 还有一些特定于内置数学运算符的魔法,它神奇地假设类型int
没有其他约束 .(+)
只是所有F#中最特殊/最神奇的东西,所以它不能很好地介绍语言/类型系统 .通常,对于静态类型的类型推断语言来说,“重载”是困难的 . F#在这里的选择非常务实 . OCaml做了一个不同的,简单的,实用的东西(没有重载) . Haskell做了一个不同的,复杂但优雅的东西(类型类) . 它们在语言/库设计领域都是有点合理的 .
必须在F#中将重载的函数(和运算符)标记为
inline
. 这是因为它们依赖于explicit member constraints . 这些约束在编译时解决 . 函数let inline add a b = a + b
的类型为'a -> 'b -> 'c (requires member (+))
,其中+
是静态函数/运算符 . 您可以't do this in C#; it doesn' t具有静态成员约束 .除了Brian的回答和链接:
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs
我在代码中找到了一些定义:
和
并且
AdditionDynamic
在这里定义(加载静态内容和CIL):https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs#L2374好玩的东西:
工作,并输出3作为输出(警告说你不应该这样做 . )