首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在不指定构造函数的情况下从列表中提取区分的联合类型?

如何在不指定构造函数的情况下从列表中提取区分的联合类型?
EN

Stack Overflow用户
提问于 2021-07-14 13:21:09
回答 4查看 83关注 0票数 1

假设我有一个由三种情况组成的有区别的联合。Case AC各自都有一个构造函数,分别为XY类型。我有一个由不同DU类型组成的列表,我想将该列表过滤为单个DU类型。目前,我有一个由ABC组成的列表。现在,如果我只想将DU列表过滤为case A类型,那么在不将构造函数传递给case A的情况下,我如何才能做到这一点呢?(或者传递一个默认的构造函数,我也不知道该怎么做)

代码语言:javascript
运行
复制
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
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-07-14 16:46:51

为了像这样过滤,我们需要DU构造函数的对立面,它是一个主动识别器。

不幸的是,您必须手动创建它们,尽管我曾建议使用F#编译器derive them automatically,但这是一个很好的例子,说明了为什么这种建议很重要。

代码语言:javascript
运行
复制
// 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|_|)

结果

代码语言:javascript
运行
复制
val filteredDUList : List<DU> = [A { Id = "1"
                                     Name = "Test" }; A { Id = "2"
                                                          Name = "Test 2" }]

不用说,你可以用普通函数代替主动识别器,因为在这个用法中,我们根本没有使用模式匹配,我的意思是,你可以按照建议将函数命名为tryA,而不是(|A|_|)

票数 2
EN

Stack Overflow用户

发布于 2021-07-14 13:28:34

没有办法在一般情况下制作这样的过滤器。我会做的是

代码语言:javascript
运行
复制
let filteredDUList =
    listDU |> List.filter (function A _ -> true | _ -> false)

如果要提取所有X,可以执行以下操作:

代码语言:javascript
运行
复制
listDU |> List.choose (function A x -> Some(x) | _ -> None)
票数 4
EN

Stack Overflow用户

发布于 2021-07-14 15:22:52

另一个版本:与@brianberns解决方案(我认为这是一个很好的解决方案)不同,它没有使用反射。它需要创建虚拟值来定义筛选条件,就像在op中一样。

这个解决方案和所有其他解决方案都不是很好的f#代码,应该有更好的方法来实现您想要实现的目标。

代码语言:javascript
运行
复制
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))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68372432

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档