在F#运算符中,重载似乎很强大,但要正确就很难。我有以下课程:
type Value<'T> =
with
static member inline (+) (a : Value<'U>, b: Value<'U>) : Value<'U> =
do stuff
Run Code Online (Sandbox Code Playgroud)
如果我用+为+定义另一个重载:
static member inline (+) (a : Value<'U>, b: 'U) : Value<'U> =
do stuff
Run Code Online (Sandbox Code Playgroud)
有用。但是如果我想要一个对称运算符:
static member inline (+) (b: 'U, a : Value<'U>) : Value<'U> =
do stuff
Run Code Online (Sandbox Code Playgroud)
编译器抱怨:
let a = Value<int>(2);
let b = a + 3 // ok
let c = 3 + a //<-- error here
Run Code Online (Sandbox Code Playgroud)
错误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
Run Code Online (Sandbox Code Playgroud)
更新
我发现了另一个我更喜欢的解决方法,因为它不需要重新定义(+)运算符,诀窍是创建一个基类并在其中移动一些重载:
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
Run Code Online (Sandbox Code Playgroud)