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?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With