2017-09-02 22 views
4

假設我有一個很大的區分聯合類型:在F#中,是否可以檢查兩個值是否具有相同的構造函數?

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 

有沒有寫在一個整潔的功能的方式,不需要短的方式我列出每一個構造函數?

+3

你可以使用[反映](https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/reflection):'讓comp ab = a.GetType()= b.GetType()' – Funk

+0

@Funk我沒有意識到它會非常簡潔。這是否有缺點? – TheQuickBrownFox

+1

@TheQuickBrownFox:它利用了DU案例如何編譯成IL中的嵌套類。從實際的角度來看,這不是一個巨大的缺點,但重要的是要認識到F#結構如何編譯到IL中(這並不總是直截了當),因爲這是使用反射API時工作的層。 – scrwtp

回答

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) 

注意:你也可以用反射來做這件事,但通常最好避免。

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 
相關問題