2012-10-05 80 views
0

我有一個歧視的聯盟,我希望爲它使用像> < compare max這樣的內置運營商。內置「< >比較」不適用於「IComparable <T>」?

[<CustomComparison>] 
type SymbolType = 
    | A 
    | B 
    | C 
    | D 

    interface IComparable<SymbolType> with 
     member x.CompareTo y = 
      match x, y with 
      | A, A-> 0 
      | A, _ -> 1 
      | _, A-> -1 
      | _, _ -> 0 

我明白我可以使用IComparable,但後來我不得不做一個null檢查,更糟糕的是,我要投它像(SymbolType) y我以爲會很耗時。

+0

可能重複[F# - >實現IComparable的HashSet的<'a>( http://stackoverflow.com/questions/5557899/f-implement-icomparable-for-hashseta) – ildjarn

回答

1

你可以只實現所需的方法與薄包裝:

[<CustomComparison>] 
[<CustomEquality>] 
type SymbolType = 
    | A 
    | B 
    | C 
    | D 
    override x.Equals y = 
     match y with 
     | :? SymbolType as t -> (((x :> IComparable<_>).CompareTo) t)=0 
     | _ -> false 
    interface IComparable with 
     member x.CompareTo y = 
      match y with 
      | :? SymbolType as t -> ((x :> IComparable<_>).CompareTo) t 
      | _ -> failwith "bad comparison" 
    interface IComparable<SymbolType> with 
     member x.CompareTo y = 
      match x, y with 
      | A, A-> 0 
      | A, _ -> 1 
      | _, A-> -1 
      | _, _ -> 0 

這樣做避免任何重複的打字。

+0

在你的代碼之後,爲什麼我不能使用'A.CompareTo B'?它說'CompareTo'沒有被定義? – colinfang

+0

@colinfang你必須編寫'(A:> IComparable).CompareTo(B)',因爲接口是隱式實現的(方法是隱藏的)。 –

+0

@TomasPetricek:你的意思是_explicitly_? – Daniel

0

在CLR上,運算符是靜態函數,因此您無法在界面中定義它們。但是如果你使用接口作爲泛型函數的類型參數的約束,也可以避免裝箱。

int Compare<T>(T lhs, T rhs) where T : IComparable<T> 
{ 
    return lhs.CompareTo(rhs) // no boxing 
} 

對不起,我不熟悉F#,所以我用C#編寫了這個例子。

+0

在F#中的等價物是'let inline compare(a:'t:> IComparable <'t>)(b:'t)= a.CompareTo(b)' –

3

你可以已經使用類型的標準比較運算符。內置的實現使用個案的聲明的順序,因此:

type SymbolType = A | B | C | D 

// Behavior of built-in comparison 
A < B = true 
D <= C = false 
max B D = D 

這看起來非常脆弱,所以也許這是不依賴於最好的事情。如果您有不包含其他值的情況下,你可以使用枚舉而不是識別聯合和定義命令你想:

type SymbolType = 
    | A = 1 
    | B = 2 
    | C = 4 
    | D = 3 

// The order is now defined by your code 
SymbolType.C < SymbolType.D = false