假设我有一个由三种情况组成的有区别的联合。Case A和C各自都有一个构造函数,分别为X和Y类型。我有一个由不同DU类型组成的列表,我想将该列表过滤为单个DU类型。目前,我有一个由A、B和C组成的列表。现在,如果我只想将DU列表过滤为case A类型,那么在不将构造函数传递给case A的情况下,我如何才能做到这一点呢?(或者传递一个默认的构造函数,我也不知道该怎么做)
type X = {
Id: string
Name: string
}
type Y = {
Id: int
}
type DU =
| A of a:X
| B
| C of b:Y
let extractDUTypesFromList (listDU: List<DU>) (typ: DU) : List<DU> =
listDU
|> List.filter (fun m -> m = typ)
let a = (A {Id = "1"; Name = "Test"})
let aa = (A {Id = "2"; Name = "Test 2"})
let b = B
let c = (C {Id = 1})
let listDU: List<DU> = [a; b; c; aa]
let filteredDUList: List<DU> = // this list will only contain case A
extractDUTypesFromList listDU (A _) // doesn't work发布于 2021-07-14 16:46:51
为了像这样过滤,我们需要DU构造函数的对立面,它是一个主动识别器。
不幸的是,您必须手动创建它们,尽管我曾建议使用F#编译器derive them automatically,但这是一个很好的例子,说明了为什么这种建议很重要。
// Active recognizers (ideally autogenerated)
let (|A|_|) = function | A x -> Some x | _ -> None
let (|B|_|) = function | B -> Some () | _ -> None
let (|C|_|) = function | C x -> Some x | _ -> None
let inline extractDUTypesFromList (listDU: List<DU>) (typ: DU -> Option<'t>) : List<DU> =
listDU
|> List.choose (fun x -> typ x |> Option.map (fun _ -> x))
let a = (A {Id = "1"; Name = "Test"})
let aa = (A {Id = "2"; Name = "Test 2"})
let b = B
let c = (C {Id = 1})
let listDU: List<DU> = [a; b; c; aa]
let filteredDUList: List<DU> = // this list will only contain case A
extractDUTypesFromList listDU (|A|_|)结果
val filteredDUList : List<DU> = [A { Id = "1"
Name = "Test" }; A { Id = "2"
Name = "Test 2" }]不用说,你可以用普通函数代替主动识别器,因为在这个用法中,我们根本没有使用模式匹配,我的意思是,你可以按照建议将函数命名为tryA,而不是(|A|_|)。
发布于 2021-07-14 13:28:34
没有办法在一般情况下制作这样的过滤器。我会做的是
let filteredDUList =
listDU |> List.filter (function A _ -> true | _ -> false)如果要提取所有X,可以执行以下操作:
listDU |> List.choose (function A x -> Some(x) | _ -> None)发布于 2021-07-14 15:22:52
另一个版本:与@brianberns解决方案(我认为这是一个很好的解决方案)不同,它没有使用反射。它需要创建虚拟值来定义筛选条件,就像在op中一样。
这个解决方案和所有其他解决方案都不是很好的f#代码,应该有更好的方法来实现您想要实现的目标。
type X = {
Id: string
Name: string
}
with static member Empty = { Id=""; Name="" }
type Y = {
Id: int
}
with static member Empty = { Id=0 }
type DU =
| A of a:X
| B
| C of b:Y
with
static member IsSameCase a b =
match a, b with
| A _, A _ -> true
| B, B -> true
| C _, C _ -> true
| _ -> false
let extractDUTypesFromList (listDU: List<DU>) (case: DU) : List<DU> =
listDU
|> List.filter (DU.IsSameCase case)
let a = (A {Id = "1"; Name = "Test"})
let aa = (A {Id = "2"; Name = "Test 2"})
let b = B
let c = (C {Id = 1})
let listDU: List<DU> = [a; b; c; aa]
let filteredDUList: List<DU> = // this list will only contain case A
extractDUTypesFromList listDU ((A (X.Empty)))
extractDUTypesFromList listDU ((A (X.Empty)))
extractDUTypesFromList listDU B
extractDUTypesFromList listDU (C (Y.Empty))https://stackoverflow.com/questions/68372432
复制相似问题