F # -> Реализовать IComparable для HashSet

#f#

#f#

Вопрос:

Возможно ли это как-то реализовать IComparable для HashSet<'a> ? Причина этого в том, что у меня объявлена следующая запись:

 [<StructuralComparison>]
type Category = { 
    mutable Id: string; 
    Name: string; 
    SavePath: string;
    Tags: HashSet<Tag> }

and Tag = { Tag:string; }
  

Как вы можете видеть, тогда теги в Category записи имеют тип HashSet<Tag> — и для того, чтобы отобразить последовательность категорий на карту, мне нужно IComparable как-то реализовать … иначе это просто приведет к:

Структура, запись или тип объединения ‘Category’ имеет атрибут ‘StructuralComparison’, но тип компонента ‘HashSet’ не удовлетворяет ‘сравнению’

Пожалуйста, обратите внимание, что я не могу использовать ничего другого, кроме a HashSet<'a> , поскольку база данных, с которой я работаю, вообще не понимает никаких списков в формате fsharp.

Ответ №1:

Я предположу, что вы хотите сравнить и приравнять Category s, принимая во внимание только Id , Name и SavePath (в таком порядке), заставляя запись вести себя так, как будто Tags ее нет:

 open System
open System.Collections.Generic

[<CustomComparison; CustomEquality>]
type Category =
    { mutable Id : string;
      Name       : string;
      SavePath   : string;
      Tags       : HashSet<Tag> }
    member private this.Ident = this.Id, this.Name, this.SavePath
    interface IComparable<Category> with
        member this.CompareTo other =
            compare this.Ident other.Ident
    interface IComparable with
        member this.CompareTo obj =
            match obj with
              | null                 -> 1
              | :? Category as other -> (this :> IComparable<_>).CompareTo other
              | _                    -> invalidArg "obj" "not a Category"
    interface IEquatable<Category> with
        member this.Equals other =
            this.Ident = other.Ident
    override this.Equals obj =
        match obj with
          | :? Category as other -> (this :> IEquatable<_>).Equals other
          | _                    -> false
    override this.GetHashCode () =
        hash this.Ident

and Tag = { Tag : string; }
  

Однако, если вместо этого вы хотите сравнить по Name и приравнять по Id , тогда рассмотрите следующее:

 open System
open System.Collections.Generic

[<CustomComparison; CustomEquality>]
type Category =
    { mutable Id : string;
      Name       : string;
      SavePath   : string;
      Tags       : HashSet<Tag> }
    interface IComparable<Category> with
        member this.CompareTo { Name = name } =
            this.Name.CompareTo name
    interface IComparable with
        member this.CompareTo obj =
            match obj with
              | null                 -> 1
              | :? Category as other -> (this :> IComparable<_>).CompareTo other
              | _                    -> invalidArg "obj" "not a Category"
    interface IEquatable<Category> with
        member this.Equals { Id = id } =
            this.Id = id
    override this.Equals obj =
        match obj with
          | :? Category as other -> (this :> IEquatable<_>).Equals other
          | _                    -> false
    override this.GetHashCode () =
        this.Id.GetHashCode ()

and Tag = { Tag : string; }
  

Ответ №2:

Смотрите

https://learn.microsoft.com/en-gb/archive/blogs/dsyme/equality-and-comparison-constraints-in-f

Вкратце, я думаю, вы хотите применить атрибуты CustomEquality и CustomComparison к этому типу, а затем реализовать его самостоятельно.