2014-03-14 77 views
3

在F#中,操作符重載看起來很強大,但也很難得到正確的結果。 我有以下類:F#操作符重載謎語2

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

感謝

回答

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 

UPDATE

我找到了另一個解決辦法,因爲這是我喜歡不需要重新定義符(+),關鍵是要建立一個基類,還可以將一些重載有:

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 
+0

嗨古斯塔沃,謝謝你的這個把戲。我認爲這是唯一的解決方法。如果我有更多類型,如價值<'T>,這個技巧會工作嗎? – Liviu

+0

我不知道的事情:A)你可以定義三元運算符。這是一個黑客。 B)雖然?< - 與記錄參數是三元的,但如果我將它稱爲(?< - )(sum,a,b),它不會編譯... – Liviu

+0

是的,它可能適用於更多類型,但它不是直截了當的。除(?< - )以外,您不能定義三元運算符,調用它的方式是(?< - )a b c或? (b)< - c沒有元組調用。 – Gustavo

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 

我說寫一個操作符重載,並做圖案裏面類型的匹配?醜,我知道。