F#与运算符重载:(>)和(^)

3

好的,那么有人可以解释一下为什么 F# 允许你重载 > 和 ^ 操作符,但不允许你使用它们吗?

+ (op_Addition): Works just fine.
^ (op_Concatenate): Compiler error in F#. Apparently only strings can be concatenated.
> (op_GreaterThan): Runtime Error – Failure during generic comparison: the type Program+OppTest4 does not implement the System.IComparable interface.

如果我将我的F#代码编译为库并从VB中使用这些运算符,它们都可以正常工作。如果我从C#中使用这些运算符,除了op_Concatenate之外,其他都不起作用(如预期的那样)。但是F#不仅忽略了其中一些,而且静态类型检查器甚至不会告诉您它计划这样做。
type OppTest4(value: int) =
   member this.value = value
   static member (^) (left : OppTest4, right : OppTest4) =
     OppTest4( Int32.Parse( left.value.ToString() ^ right.value.ToString()  ))
   static member (+) (left : OppTest4, right : OppTest4) =
     OppTest4(left.value + right.value )
   static member (>) (left : OppTest4, right : OppTest4) =
     left.value > right.value
   static member (<) (left : OppTest4, right : OppTest4) =
     left.value < right.value
2个回答

4

F#对这些运算符符号有默认的含义,这对于F#是合理的。您可以始终定义自己的含义来覆盖默认值,例如:

let (>) x y = ...

例如,您可以定义这个运算符为“T.operator>(U)”(假设x具有类型T,y具有类型U)。
请参见源代码分发中FSharp.Core中的prim-types.fs文件以获取默认定义。(它们非常复杂!)
由于(1)CLR不支持类似于类型类的机制(用于定义一组无关类型之间的公共语义),以及(2)原始类型(如'int')在任何编程语言实现中通常需要进行特殊处理(例如,System.Int32没有定义operator+方法,但大多数编程语言选择表现得好像存在这样的方法),因此很难想象在.Net上所有语言之间有任何通用的运算符。根据一个语言选择做什么(在这里总结了太多相互作用的问题)。无论如何,您应该能够从F#调用任何方法,如果默认运算符行为不理想,则可以重新定义(影响)所需的运算符行为。如果您有特定的场景想法,而且无法使其正常工作,请告诉我。
编辑
我在http://cs.hubfs.net/forums/thread/10869.aspx上添加了更多细节。

好的,那么为什么这个不起作用呢?“静态成员 (>) (left: OppTest4, right: OppTest4) = left.value > right.value” - Jonathan Allen
很难想象在.Net上有任何通用的跨语言操作符。但是,如果您使用我在问题中展示的代码,VB将支持所有操作符。F#正在发出标准的IL代码,只是没有消耗它。 - Jonathan Allen
我很好奇是否可以使用let绑定仅为一种类型阴影默认操作符定义 - 我无法控制类型实现。如果可以,应该如何实现? 我尝试过 let (>) (a:SomeType) (b:SomeType) = ... 但是这样做会导致其他类型之间的任何比较都无法编译,因此 2 > 1 就不能再编译了。 - em70
1
@emaster,你不能只为一个类型进行阴影处理。大家好,如果我能在接下来的一周里抽出几个小时的时间,我会尝试写一篇关于这个问题的博客,因为有很多不同的相互作用的力量在起作用。 - Brian
1
与此同时,其他人在 http://cs.hubfs.net/forums/thread/10860.aspx 上发布了一个不错的摘要。 - Brian
@Brian,你分享的链接都失效了 =( - Maslow

0

我同意,这里存在不一致性:操作符可以被定义,但不能被使用。

你是否在问为什么F#设计者决定实现与System.IComparable接口的比较而不是操作符重载?我不知道为什么,在面向对象的语言中,我更喜欢IComparable而不是操作符重载。因此,我建议F#开发人员打破C#兼容性,并禁止“static member (>) (...)”语法糖。

如果您想知道如何调用这些重载的操作符,那很容易:使用op_Concatenate、op_GreaterThan或op_LessThan静态成员即可。(实际上,我收到了一个编译器警告,描述了这个问题。F# 1.9.6.16)

运行时错误将System.IComparable强制转换而没有任何编译器警告绝对是一个bug。您可以将其发送到fsbugs@microsoft.com。


运行时错误不是一个 bug,它是按设计实现的。我还没有看到过对这个设计的公开讨论,尽管它很有动机即使不明显,所以我会尽快试着纠正这个问题。 - Brian
好的,无法证明每个OppTest4实例都没有IComparable接口。但是仍然知道有些OppTest4实例无法转换为IComparable!因此至少应该有一个警告!为什么不呢? - vpolozov
@.vpolozov.name:看起来F#规范的第9.6节(http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec2.aspx)表明,他们正在考虑在某些情况下添加警告,以防止使用比较运算符可能会失败。 - kvb
@kvb 看起来链接已经失效了 =( - Maslow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接