F#运算符重载谜语2

时间:2014-03-14 09:32:55

标签: f#

在F#中,运算符重载似乎很强大,但也很难搞定。 我有以下课程:

 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

由于

2 个答案:

答案 0 :(得分:4)

删除类型注释将解决您指出的问题,但您没有注意到还有另一个问题:尝试调用第一个重载,编译器将不知道要调用哪个重载。很遗憾,重载决议并没有找到合适的解决方案。

在编译时使一切正常工作的一个棘手方法是仅声明类型中的第一个重载,其余使用使用中间类型重新定义(+)运算符的技巧:

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

答案 1 :(得分:0)

我认为问题在于,当第二个重载的第二个参数本身为Value<'T>时,第一个和第二个重载之间无法解决。

以下是导致错误的完整版本:

type Value<'T>(v : 'T) =
    member x.V = v
    with
        static member inline  (+) (a : Value<'U>, b: Value<'U>) : Value<'U> = 
            Value<'U>(b.V+a.V)

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

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


let a = Value<int>(2);
let b = a + 3
let c = 3 + a

我会说写一个运算符重载,并在其中的类型上进行模式匹配吗?我知道,丑陋。