Reputation: 581
Assuming I have a big discriminated union type:
type Thing =
| One of int
| Two of string
| Three of bool option
...
And I have this function:
let comp a b = match a, b with
| One _, One _ -> true
| Two _, Two _ -> true
...
| _, _ -> false
Is there a way to write the function in a neater, shorter way that doesn't require me to list every single constructor?
Upvotes: 4
Views: 573
Reputation: 11362
I'm not quite sure how good it is performance-wise, but it is possible to do this using 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
Use:
> isSameThingCase (One 1) (One 2);;
val it : bool = true
> isSameThingCase (Two "test") (Three None);;
val it : bool = false
Upvotes: 3
Reputation: 10624
Basically, this is not possible. Even if you could get the constructors for your values, they are not comparable because they are functions. There's a bit of boilerplate involved but you could define tag values and a function to map to the tags:
let thingCase thing =
match thing with
| One _ -> 1
| Two _ -> 2
| Three _ -> 3
let comp a b = thingCase a = thingCase b
This is flexible enough to work on sequences too:
let compSeq things =
things
|> Seq.map thingCase
|> Seq.pairwise
|> Seq.forall (fun (a, b) -> a = b)
Note: you could also do this with reflection but it's generally best to avoid.
Upvotes: 4