2015-12-06 33 views
6

F#新手问题。 我有歧视工会等的列表: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 

我怎么能做出这样的通用功能在通话 所需的输出类型指定(类型1 |类型2 |类型3)?

+0

您的问题已解决? –

回答

8

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

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

choose是像地图和过滤器相结合,为每一个元件,其中该结果是Some并忽略它在哪里None所有元素返回f(x)。在这个例子中,返回类型是Type1 list


Parametrising根据特定的情况下,工会的功能是不可能的,这是因为特定的工会的情况下都没有自己的类型,它们仅仅是为联盟类型构造。你的例子中的T1不是一种类型,但是Union1是。这意味着,在某些时候,需要显式模式匹配来分解它。 (请注意,在所有函数式语言中都不是这样,Scala的union案例是用继承来建模的,但F#采用了Haskell,Ocaml等使用的方法)。

正如陀Soikin提到的,你可以写一个静态成员或要检查每一种情况下,如果你愿意的话,作为一个例子的功能:

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

然后,您可以使用此语法:

lst1 |> List.choose (tryAssumeT1) 
+0

谢谢,这很好,很短。 但似乎我仍然需要编写单独的表达式(函数)来过滤出Type1,Type2和Type3的项目? 是否可以使用所需的类型创建参数化函数? – RobF

+0

你可以通过为你的'Union1'类型提供存取函数来很好地编码它,比如'static member t1 = function T1 t - > Some t | _ - > None“,然后将它们用作List.choose的参数,比如List.choose Union1.t1。 –

+0

工作正常! 但我首先必须声明Type1,然后联合构造函数T1 .. T3,并且只有之后添加静态 “匹配”功能的类型Type1 .. Type2。 这是正确的吗? – RobF