F# operator overloading riddle 2

佐手、 提交于 2019-12-06 07:05:42

问题


In F# operator overloading seems powerful but also tricky to get right. I have following class:

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

If i define another overload for + with :

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

It works. But if i want a symmetric operator:

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

The compiler complains:

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

Error 3 Type inference problem too complicated (maximum iteration depth reached). Consider adding further type annotations

Is there a way around this and stay generic?

I am using F# 3.1

Thanks


回答1:


Removing the type annotations will solve the issue you pointed out, but you didn't notice there is another issue: try invoking the first overload, the compiler will not know which overload to call. It's a shame the overload resolution doesn't pick up the right one.

One tricky way to get everything working at compile time is to declare only the first overload into the type, and for the rest use the trick of redefining the (+) operator using an intermediate type:

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

UPDATE

I've found another workaround which I prefer since it does not require redefining the (+) operator, the trick is to create a base class and move some overloads there:

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



回答2:


I think the problem lies in the fact that there is no way to resolve between the first and, say, the second overload when the second parameter to the second overload is a Value<'T> itself.

Here is a complete version that causes the error:

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

I'd say write one operator overload, and do pattern matching on type inside it? Ugly, I know.



来源:https://stackoverflow.com/questions/22401010/f-operator-overloading-riddle-2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!