Say I have a list of shapes:
type shape =
| Circle of float
| Rectangle of float * float
let a = [ Circle 5.0; Rectangle (4.0, 6.0)]
How can I then test e.g. a Circle exists in a? I could create a function for each shape
let isCircle s =
match s with
| Circle -> true
| _ -> false
List.exists isCircle a
but I feel there must be a more elegant way in F#, other than having to define such a function for each shape type. Is there?
Related question is how to group a list of shapes, based on shape types:
a |> seq.groupBy( <shapetype? >)
If you're interested in the different categories of shapes, then it makes sense to define another type that exactly captures them:
Edit - as suggested by Brian, you can alternatively use active patterns instead of a new type. It works out pretty similarly for your examples, but would extend better to more complicated patterns, while the approach above may be better if you're code often works with the categories, and you want a nice union type for them instead of a Choice type.
A more elegant solution could be the following:
However, I'm not very satisfied with this myself since you have to create an instance of the discriminated union for it to work.
Grouping by shape type could work in a similar fashion.
I want to add another solution that works with quotations for every union case, based on the one desco provided. Here it goes:
Defined this way, isUnionCase works like desco has shown, but even on union cases that are empty or have more than one value. You can also enter a tuple of comma-separated union cases. Consider this:
The first isUnionCase I provided only worked for single case checks. I later added the expression check for NewTuple and thought you might like it. Just make sure that if you alter the code the precomputations still work, this is why
iucs
is defined outside of the returned anonymous function.You can use the F# reflection library to get a value's tag:
you can combine F# reflection with quotations to get generic solution