对受歧视的联合实施 F# 比较
Implementing F# comparison on disciminated unions
我有一个日志级别类型:
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
// ...
The type 'LoggingLevel' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface
我这里怎么出错了?
我设法让它工作了,但是现在类型定义太冗长了!一定有更好的方法...
[<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)
我认为你的比较实现是基于输入的。以下为我编译:
[<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
I would like to say that some logging levels are higher than others. For example, Trace
is higher than 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 ✔
更多信息:
我有一个日志级别类型:
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
// ...
The type 'LoggingLevel' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface
我这里怎么出错了?
我设法让它工作了,但是现在类型定义太冗长了!一定有更好的方法...
[<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)
我认为你的比较实现是基于输入的。以下为我编译:
[<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
I would like to say that some logging levels are higher than others. For example,
Trace
is higher thanInfo
.
您是否需要使用自定义相等和自定义比较? 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 ✔
更多信息: