F#运算符重载之谜2

标签 f#

在 F# 中,运算符重载似乎很强大,但也很难做到正确。 我有以下类(class):

 type Value<'T> = 
    with
        static member inline  (+) (a : Value<'U>, b: Value<'U>) : Value<'U> = 
           do stuff

如果我为 + 定义另一个重载:

static member inline  (+) (a : Value<'U>, b: 'U) : Value<'U> = 
           do stuff

它有效。但是如果我想要一个对称运算符:

static member inline  (+) (b: 'U, a : Value<'U>) : Value<'U> = 
           do stuff

编译器提示:

let a = Value<int>(2);
let b = a + 3 // ok
let c = 3 + a //<-- error here

错误 3 类型推断问题太复杂(达到最大迭代深度)。考虑添加更多类型注释

有没有办法解决这个问题并保持通用性?

我正在使用 F# 3.1

谢谢

最佳答案

删除类型注释将解决您指出的问题,但您没有注意到还有另一个问题:尝试调用第一个重载,编译器将不知道调用哪个重载。遗憾的是,重载决议没有选择正确的决议。

让所有东西在编译时工作的一个巧妙方法是只声明类型的第一个重载,其余的使用使用中间类型重新定义 (+) 运算符的技巧:

type Value<'T> = Value of 'T with
    static member inline  (+) (Value a, Value b) = Value (a + b)

type Sum = Sum with
    static member inline (?<-) (Sum, a, b) = a + b
    static member inline (?<-) (Sum, Value a, b) = Value (a + b)
    static member inline (?<-) (Sum, b, Value a) = Value (a + b)

let inline (+) a b :'t = (?<-) Sum a b

// test
let v = Value(2)
let a = v + v
let b = v + 3
let c = 3 + v
let d = Value(Value 7) + Value(Value 10)
let e = 5 + 7

更新

我找到了另一个我更喜欢的解决方法,因为它不需要重新定义 (+) 运算符,诀窍是创建一个基类并在那里移动一些重载:

type BaseValue<'T>(v : 'T) =
    member x.V = v

type Value<'T>(v : 'T) =
    inherit BaseValue<'T>(v : 'T)
    static member inline  (+) (a : Value<_>, b: Value<_>) = Value(b.V+a.V)

type BaseValue with
    static member inline  (+) (a: BaseValue<_>, b) = Value(b+a.V)
    static member inline  (+) (b, a: BaseValue<_>) = Value(b+a.V)


// test
let v = Value(2)
let a = v + v
let b = v + 3
let c = 3 + v
let d = Value(Value 7) + Value(Value 10)
let e = 5 + 7

关于F#运算符重载之谜2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22401010/

相关文章:

f# - 如何将字典条目的值声明为可变的?

F# 柯里化(Currying)函数的有趣行为

class - 在 F# 中使用私有(private)构造函数创建一个类

winforms - 关于为饼图创建标签的 F# 说明

f# - pretty-print 一棵树

regex - 这个正则表达式有什么问题? (使用 '.' )

f# - 如何统一该成员方法和内联函数的签名

f# - F#中的尾递归:堆栈溢出

debugging - 盲源步进的奥秘,或F#在大型源文件上的行为异常

F# 比较与 C# IComparable