F # general filter filter list with discriminatory unions

F # newbie question. I have a list of discriminatory 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 to indicate the required output type (Type1 | Type2 | Type3) in a call?

+6
source share
1 answer

My approach will probably just use List.choose or Seq.choose . It has advantages over filter/map because you only need to match the pattern once, and this is much more concise than fold .

 lst1 |> List.choose (function |T1 res -> Some res |_ > None) 

choose is something like a map and a combined filter, it returns f(x) for each element where this result was Some , and ignores all elements where it was None . In this example, the return type is Type1 list .


Parameterization of a function based on a specific case of a union is impossible, this is due to the fact that special cases of a union are not the types themselves, they simply are constructors for the type of the union. T1 in your example is not a type, but Union1 is. This means that at some point, its decomposition requires explicit pattern matching. (Note that this does not apply to all functional languages, Scala combining cases are modeled with inheritance, but F # uses the approach used by such as Haskell, Ocaml, etc.).

As Fedor Soikin mentioned, you can write a static member or function to check for each case, if you want, as an example:

 static member tryAssumeT1 = function |T1 t1 -> Some t1 | _ -> None 

Then you can use this syntax:

 lst1 |> List.choose (tryAssumeT1) 
+8
source

All Articles