Frequently one wants to iterate (with either map, iter, or fold) through a collection of heterogeneous objects (different types). One way to deal with this is to create a discriminated union, which allows one to create a list with the objects suitably converted to DU cases. The following code does that in a simple example:
type MYDU = | X1 of int
| X2 of float
| X3 of string
let bar (y: MYDU) =
match y with
| X1 x -> printfn "%A" x
| X2 x -> printfn "%A" x
| X3 x -> printfn "%A" x
[X1(1); X2(2.0); X3("3"); X1(4)]
|> List.map bar |> ignore
This code runs fine and prints
1
2.0
"3"
4
Great! But I wonder if one can avoid repeating the call to printfn
. I tried the following and it does not compile:
let baz (y: MYDU) =
match y with
| X1 x | X2 x | X3 x -> printfn "%A" x // red squiggly line under X1 x
The compiler issues this message:
This expression was expected to have type 'int' but here has type 'float'
I suspect avoiding repetition is feasible but I must be making a basic mistake. Any suggestions?
You're not making a mistake there, it's just not something F#'s type system would allow.
You can have multiple patterns on the left side of the match case arrow, but they are required to bind the same set of values (incl. the types). Here, x
has a different type for each pattern, and that's enough for the compiler to complain.
There are ways to alleviate the pain (you could have a member on the DU that would return a boxed value, or you could have an active pattern that would do the boxing in the match case), but they're highly situational. Splitting the patterns into separate cases and repeating the right side for each one of them is always a better solution in a vacuum.
Something you could do instead is convert your arguments to a common type for printing, then print that value out instead. And you still get the advantages of pattern matching and discriminated unions :)
Here is an example of this approach
type MYDU =
| X1 of int
| X2 of float
| X3 of string
let bar y =
let myStr =
match y with
| X1 x -> string x
| X2 x -> string x
| X3 x -> x
printfn "%s" myStr
bar (X1 5)
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