F#通用函数筛选受歧视联合的列表

时间:2015-12-06 17:46:54

标签: generics filter f# 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 

如何使这样的函数通用以在调用中指定 所需的输出类型(Type1 | Type2 | Type3)?

1 个答案:

答案 0 :(得分:9)

我的方法可能只是使用List.chooseSeq.choose。它优于filter/map,因为您只需要执行一次模式匹配,它比fold简洁得多。

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

choose类似地图和过滤器,它会为结果为f(x)的每个元素返回Some,并忽略所有None元素。在此示例中,返回类型为Type1 list

基于特定联合情况对函数进行参数化是不可能的,这是因为特定的联合情况本身不是类型,它们只是联合类型的构造函数。您示例中的T1不是类型,但是Union1。这意味着,在某些时候,需要显式模式匹配来分解它。 (请注意,并非所有函数式语言都是如此,Scala的并集案例使用继承建模,但F#采用Haskell,Ocaml等方法使用的方法。)

正如Fyodor Soikin所提到的,如果你愿意,你可以写一个静态成员或函数来检查每个案例,例如:

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

然后您可以使用以下语法:

lst1 |> List.choose (tryAssumeT1)