F# -> Implement IComparable for HashSet<'a>

扶醉桌前 提交于 2019-12-20 02:58:13

问题


Is it possible to somehow implement IComparable for a HashSet<'a>? The reason for this is that I have following record declared:

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

and Tag = { Tag:string; }

As you can see, then Tags in the Category record is of type HashSet<Tag> - and in order to map a sequence of Categories to a Map, I'll need to implement the IComparable somehow... else it will just result in:

The struct, record or union type 'Category' has the 'StructuralComparison' attribute but the component type 'HashSet' does not satisfy the 'comparison'

Please note that I cant use anything else than a HashSet<'a> since the database I'm working with dosent understand any fsharp-ish lists at all.


回答1:


I'll assume you want to compare and equate Categorys by taking only Id, Name, and SavePath into account (in that order), making the record behave as though Tags wasn't present:

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; }

However, if instead you want to compare by Name and equate by Id then consider the following:

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:


See

http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx

Briefly I think you want to apply the CustomEquality and CustomComparison attributes to this type and then implement it yourself.



来源:https://stackoverflow.com/questions/5557899/f-implement-icomparable-for-hashseta

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