在F#中,是否可以检查两个值是否具有相同的构造函数?

时间:2017-09-02 13:53:27

标签: function f# functional-programming pattern-matching

假设我有一个很大的歧视联盟类型:

type Thing =
    | One of int
    | Two of string
    | Three of bool option
      ...

我有这个功能:

let comp a b = match a, b with
    | One _, One _ -> true
    | Two _, Two _ -> true
      ...
    | _, _ -> false

有没有办法以更简洁的方式编写函数,不需要我列出每一个构造函数?

2 个答案:

答案 0 :(得分:3)

基本上,这是不可能的。即使您可以获得值的构造函数,它们也不具有可比性,因为它们是函数。这里有一些样板文件,但你可以定义标签值和一个映射到标签的函数:

let thingCase thing =
    match thing with
    | One _ -> 1
    | Two _ -> 2
    | Three _ -> 3

let comp a b = thingCase a = thingCase b

这足够灵活,可以处理序列:

let compSeq things =
    things
    |> Seq.map thingCase
    |> Seq.pairwise
    |> Seq.forall (fun (a, b) -> a = b)

注意:您也可以使用反射进行此操作,但通常最好避免使用。

答案 1 :(得分:2)

我不太确定它在性能方面有多好,但可以使用FSharp.Reflection执行此操作。

open FSharp.Reflection

type Thing =
    | One of int
    | Two of string
    | Three of bool option

let tagOfThing = FSharpValue.PreComputeUnionTagReader(typeof<Thing>)
// val tagOfThing : obj -> int

let isSameThingCase (a: Thing) (b: Thing) =
    tagOfThing a = tagOfThing b

使用:

> isSameThingCase (One 1) (One 2);;
val it : bool = true
> isSameThingCase (Two "test") (Three None);;
val it : bool = false