Rob*_*obF 6 generics f# filter unions
F#新手问题.我有一个受歧视的工会清单,如:
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
Run Code Online (Sandbox Code Playgroud)
如何使这样的函数通用以在调用中指定所需的输出类型(Type1 | Type2 | Type3)?
我的方法可能只是使用List.choose或Seq.choose.它有优势,filter/map因为你只需要执行一次模式匹配,它比a简洁得多fold.
lst1
|> List.choose
(function
|T1 res -> Some res
|_ > None)
Run Code Online (Sandbox Code Playgroud)
choose类似于地图和过滤器的组合,它返回f(x)结果所在的每个元素,Some并忽略它所在的所有元素None.在此示例中,返回类型是a Type1 list.
基于特定联合情况对函数进行参数化是不可能的,这是因为特定联合情况本身不是类型,它们仅仅是联合类型的构造函数. T1在你的例子中不是一个类型,但是Union1.这意味着,在某些时候,需要显式模式匹配来分解它.(请注意,并非所有函数式语言都是如此,Scala的并集案例使用继承建模,但F#采用Haskell,Ocaml等方法使用的方法).
正如Fyodor Soikin所提到的,如果你愿意,你可以写一个静态成员或函数来检查每个案例,例如:
static member tryAssumeT1 = function
|T1 t1 -> Some t1
| _ -> None
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用以下语法:
lst1 |> List.choose (tryAssumeT1)
Run Code Online (Sandbox Code Playgroud)