在有区别的工会上实施F#比较

时间:2018-12-20 11:21:49

标签: f# comparison-operators

我有一个日志记录级别类型:

type LoggingLevel =
| Trace
| Debug
| Info

我想说某些日志记录级别高于其他日志记录级别。例如,Trace高于Info

所以我像这样实现IComparable

[<StructuralEqualityAttribute>]
[<CustomComparisonAttribute>]
type LoggingLevel =
| Trace
| Debug
| Info

  interface IComparable<LoggingLevel> with
    override this.CompareTo other =
      let score x =
        match x with
        | Trace -> 0
        | Debug -> 1
        | Info -> 2
      (score this) - (score other)

但是当我尝试使用它时,出现错误:

if a >= b 
then 
  // ...
  

类型“ LoggingLevel”不支持“比较”约束。例如,它不支持“ System.IComparable”接口

我在这里怎么出错了?


我设法使其正常运行,但是现在类型定义太冗长了!一定有更好的方法...

[<CustomEquality>]
[<CustomComparisonAttribute>]
type LoggingLevel =
  | Trace
  | Debug
  | Info

  override this.Equals (obj) =
    match obj with
    | :? LoggingLevel as other ->
      match (this, other) with
      | (Trace, Trace) -> true
      | (Debug, Debug) -> true
      | (Info, Info) -> true
      | _ -> false
    | _ -> false

  override this.GetHashCode () =
    match this with
    | Trace -> 0
    | Debug -> 1
    | Info -> 2

  interface IComparable<LoggingLevel> with
    member this.CompareTo (other : LoggingLevel) =
      let score x =
        match x with
        | Trace -> 0
        | Debug -> 1
        | Info -> 2
      (score this) - (score other)

  interface IComparable with
    override this.CompareTo other =
      (this :> IComparable<LoggingLevel>).CompareTo (other :?> LoggingLevel)

2 个答案:

答案 0 :(得分:1)

我认为您正在根据类型进行比较实施。以下为我编译:

[<CustomComparison>]
[<StructuralEquality>]
type LoggingLevel =
| Trace
| Debug
| Info

    interface System.IComparable with 
        member this.CompareTo other = 
            0
            // replace 0 with your comparison logic here

let a = Trace
let b = Debug

if Trace > Debug then printfn "here"

请注意,在这种情况下,other的类型为obj,您需要进行相应的装箱。由于这里的所有案例都是空的(即缺乏类型),这使所有的问题变得棘手。

我很想看到一个更完整的示例,您正在尝试使用此逻辑。我怀疑match表达式可能会更好,并且可以删除此自定义比较。

也就是说,在不知道您确切的用例的情况下,这样的功能会更实用(也许更简单)吗?

type LoggingLevel = Trace | Debug | Info

module Logger =        
    let doSomeLogging logLevel =
        match logLevel with
        | Trace -> "trace"
        | Debug -> "debug"
        | Info -> "info"

let result = Logger.doSomeLogging Trace

答案 1 :(得分:1)

  

我想说某些日志记录级别高于其他日志记录级别。例如,Trace高于Info

您是否需要使用自定义相等性和自定义比较? F#已为歧视工会内置了这些功能。您只需要在类型定义中按升序编写它们:

type LoggingLevel =
  | Info
  | Debug
  | Trace // Note the order here! 

Trace > Info // true

let levels = [ Trace; Debug; Info; Trace; Debug; Info ]

levels |> List.sort
// [Info; Info; Debug; Debug; Trace; Trace]
// Comparison ✔

levels |> List.countBy id
// [(Trace, 2); (Debug, 2); (Info, 2)]
// Equality ✔

更多信息:results of query 2 showing removal of "second row"