Внедрение сравнения F # для исключенных союзов - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть тип для уровней ведения журнала:

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 голосов
/ 21 декабря 2018

Я хотел бы сказать, что некоторые уровни регистрации выше, чем другие.Например, 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 ✔

Дополнительная информация: https://stackoverflow.com/a/52220335/1256041

0 голосов
/ 20 декабря 2018

Я думаю, что вы сравните реализацию на основе набора текста.Следующие компиляции для меня:

[<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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...