在 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/