Built-in “< > compare” doesn't work with “IComparable<T>”?

ε祈祈猫儿з 提交于 2019-12-25 05:18:26

问题


I have a Discriminated Union, and I hope to use built in operators like > < compare max for it.

[<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

I understand I can use IComparable, but then i have to do a null check, what's worse is that I have to cast it like (SymbolType) y which I assume would be time consuming.


回答1:


You can just implement the required methods with thin wrappers:

[<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

This way does avoid any duplicate typing.




回答2:


You can already use standard comparison operators on the type. The built-in implementation uses the order of declarations of the individual cases, so:

type SymbolType =  A | B | C | D 

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

This looks very fragile, so maybe it is not the best thing to rely on. If you have cases that do not contain other values, you can use enum instead of discriminated union and define the ordering you wish:

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

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



回答3:


On CLR, operators are static functions, so you can't define them in an interface. But boxing can also be avoided if your use the interface as a constraint of type parameter of a generic function.

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

Sorry, I'm not familiar with F#, so I wrote the example in C#.



来源:https://stackoverflow.com/questions/12744831/built-in-compare-doesnt-work-with-icomparablet

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!