F#运算符重载之谜2 [英] F# operator overloading riddle 2

查看:85
本文介绍了F#运算符重载之谜2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在F#运算符中,重载似乎功能强大,但正确操作也很棘手. 我有以下课程:

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

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

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

编译器抱怨:

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

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

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

Is there a way around this and stay generic?

我正在使用F#3.1

I am using F# 3.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

更新

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

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

这篇关于F#运算符重载之谜2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆