F# newbie question. I have a list of discriminated unions like:
type Type1 = { name:string; id: int; }
type Type2 = { x: float; y: float;}
type Type3 = { x: float; naam:string}
type Union1 =
| T1 of Type1
| T2 of Type2
| T3 of Type3
let lst1 = [ T1 {name="nnn"; id=3}; T2 {x=1.1; y=1.3}; T1 {name="naam1"; id=39}; T3{x=0.0; naam="xx"}];
//To filter out items of Type1, i do:
let fltT1 (l:list<Union1>) :list<Type1> =
let rec loop (l:list<Union1>) (acc:list<Type1>) =
match l with
| h::t -> match h with
// this is now specific per type
| T1{name=n;id=i} -> loop t ({name=n;id=i}::acc)
| _ -> loop t acc
| [] -> acc
loop l [] |> List.rev
How can I make such a function generic to specify in the call the required output type (Type1|Type2|Type3)?
My approach would probably be just to use List.choose
or Seq.choose
. It has advantages over filter/map
because you only need to perform the pattern match once and it's a lot more concise than a fold
.
lst1
|> List.choose
(function
|T1 res -> Some res
|_ > None)
choose
is something like a map and a filter combined, it returns f(x)
for every element where that result was Some
and ignores all elements where it was None
. In this example, the return type is a Type1 list
.
Parametrising a function based on a particular union case is not possible, this is because particular union cases are not themselves types, they are merely constructors for the union type. T1
in your example is not a type but Union1
is. That means, at some point, an explicit pattern match is required to decompose it. (Note that this isn't true of all functional languages, Scala's union cases are modelled with inheritance but F# adopts the approach used by the likes of Haskell, Ocaml, etc.).
As Fyodor Soikin mentioned, you can write a static member or a function to check against each case if you wish, as an example:
static member tryAssumeT1 = function
|T1 t1 -> Some t1
| _ -> None
You can then use this syntax:
lst1 |> List.choose (tryAssumeT1)
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