繁体   English   中英

F#比较区分联合的案例标识符

[英]F# comparing discriminated unions' by case identifier

有没有办法通过F#中的案例标识符比较受歧视的联盟?

type MyUnion =
| MyString of string
| MyInt of int

let x = MyString("hello")
let y = MyString("bye")
let z = MyInt(25)

let compareCases a b =
// compareCases x y = true
// compareCases x z = false
// compareCases y z = false

如何以通用方式实现compareCases函数?

即如下所示,但更通用(反射是可以的):

let compareCases a b =
  match a with
  | MyString(_) -> match b with | MyString(_) -> true | _ -> false
  | MyInt(_) -> match b with | MyInt(_) -> true | _ -> false

使用GetType()的问题是,如果你有2个'无数据​​'的情况,它就会失败。

这是一种方法:(编辑因为之前的UnionTagReader没有被缓存)

type MyDU =
    | Case1
    | Case2
    | Case3 of int
    | Case4 of int

type TagReader<'T>() =
    let tr = 
        assert FSharpType.IsUnion(typeof<'T>)
        FSharpValue.PreComputeUnionTagReader(typeof<'T>, System.Reflection.BindingFlags.Public)

    member this.compareCase (x:'T) (y:'T) =
        (tr x) = (tr y)

let tr = TagReader<MyDU>()

let c1 = Case1
let c2 = Case2
let c3 = Case3(0)
let c3' = Case3(1)
let c4 = Case4(0)

assert (c1.GetType() = c2.GetType() )  //this is why you can not use GetType()

assert tr.compareCase c1 c1
assert not (tr.compareCase c1 c2)
assert tr.compareCase c3 c3'
assert not (tr.compareCase c3 c4)

首先,您可以像这样改进您的示例:

let compare = function
| MyString _, MyString _, | MyInt _, MyInt _ -> true
| _ -> false

但这是最好的方式(最小的反射!):

let compare a b = a.GetType () = b.GetType ()

这应该可以解决问题

open Microsoft.FSharp.Reflection

type MyUnion =
    | MyString of string
    | MyInt of int

let x = MyString("hello")
let y = MyString("bye")
let z = MyInt(25)

let compareCases a b =
    FSharpValue.GetUnionFields (a, a.GetType()) |> fst
        = (FSharpValue.GetUnionFields (b, b.GetType()) |> fst)

但是,为了对这些值做任何事情,你仍然需要模式匹配,所以我不太明白这一点,说实话。

let compareCases (a : MyUnion) (b : MyUnion) =
    a.GetType().Name = b.GetType().Name

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM