繁体   English   中英

如何编写F#联合类型选择器?

[英]How to write an F# union type chooser?

如果使用F#,还有更好的方法吗?

type T =
    | A of int
    | B of string
    static member chooseA x = match x with A i -> Some i | _ -> None
    static member chooseB x = match x with B s -> Some s | _ -> None

用例如下:

let collection = [A 10; B "abc"]
let aItems = collection |> Seq.choose T.chooseA
let bItems = collection |> Seq.choose T.chooseB

谢谢!

使用List.partition拆分源元素:

type T =
    | A of int
    | B of string

let collection = [A 10; B "abc"; A 40; B "120"]

let result = List.partition (function | A _ -> true | _ -> false) collection

val result : T list * T list = ([A 10; A 40], [B "abc"; B "120"])

然后,您可以使用fst和snd选择相关列表。

这很尴尬,但是我可以理解为什么它不是F#设计的重要案例。 通常,有一种解决方案允许完整的模式匹配,而不是多个(有些不完整)的模式匹配。 例如,可以这样构造两个具体的项目序列:

let aItems, bItems =
    let accA, accB = ResizeArray(), ResizeArray()
    collection |> Seq.iter (function A i -> accA.Add i | B s -> accB.Add s)
    seq accA, seq accB

如果您不喜欢,可以采用类似的无突变解决方案,但是我几乎没有理由担心封装突变。 请注意,结果强制转换为seq

这将按照其设计方式使用模式匹配:

  • 如果将另一个大小写添加到T ,则处理功能中将显示一条警告,这正是继续编辑的地方:确定如何处理新输入的大小写。
  • 该程序不必为每种输入重复多次输入,而只需遍历一次并在初次遇到时处理每个项目。

如果上述方法不合适,您仍然可以通过使用function关键字并将声明选择器函数声明为lambda来稍微缩短问题的代码。 例如:

let aItems = collection |> Seq.choose (function A i -> Some i | _ -> None)

请注意,这是惰性的,就像问题中的建议一样:在这里,对aItems每次迭代aItems将不必要地遍历输入中的所有B例。

我可以提供以下变体:

open System.Reflection

type T =
    | A of int
    | B of string

let collection = [A 10; B "abc"; A 40; B "120"]

let sp (col: T list) (str:string) = 
      if col=[] then []
      else  
        let names = "Is" + str
        col |> List.filter(fun x-> let t = x.GetType()
                                   if t.GetProperty(names) = null then false
                                   else 
                                   t.InvokeMember(names, BindingFlags.GetProperty, null, x, null) :?> bool)
            |> List.map(fun y ->
                y.GetType().InvokeMember("get_Item", BindingFlags.InvokeMethod, null, y, null))

sp collection "A" |> printfn "%A\n"
sp collection "B" |> printfn "%A\n"   
sp collection "C" |> printfn "%A\n"

打印:

[10; 40]

["abc"; "120"]

[]

http://ideone.com/yAytQk

我是F#的新手,所以我认为这可以轻松完成

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM