繁体   English   中英

在 F# 中的可区分联合中按值匹配

[英]match by value in a discriminated union, in F#

与这个联盟:

type T =
    | A
    | B
    | C

和一个T列表

我想实现类似这个伪代码的东西:

let countOfType (t: Type) (l: T list) =
    l
    |> List.filter (fun x -> x.GetType() = t)
    |> List.length

如果我想计算 'A'、'B' 等,我什么时候会通过。但是 A.GetType() 和 B.GetType() 返回 T 类型,所以这不起作用。

有没有办法通过将类型作为参数传递来检查类型?

这里的实际情况是我有一个每隔几秒更新一次的 Map 并且它的值是同一个 DU 的一部分。 我需要能够查看每种类型的数量,而不必在每次添加条目时更新代码(如匹配块)。


附录:我把原来的问题简化了太多,看到Fyodor的回答后才明白。

所以我想添加额外的部分:对于这样的情况,如何也能做到这一点:

type T =
    | A of int
    | B of string
    | C of SomeOtherType

对于您指定的枚举类型T ,您可以只使用常规比较:

let countOfType t (l: T list) =
    l
    |> List.filter (fun x -> x = t)
    |> List.length

用法:

> countOfType A [A; A; B; C; A]
3

> countOfType B [A; A; B; C; A]
1

尝试List.choose: ('a -> 'b option) -> 'a list -> 'b list ,它根据'a -> 'b option选择器过滤列表。 如果选择器评估为Some ,则将包含 value ,如果选择器评估为None ,则 value 将被跳过。 如果您担心由Some实例化引起的分配,那么您必须实现将使用ValueOption版本

    let onlyA lis =
        lis |> List.choose (function
                            | (A _) as a -> Some a
                            | _ -> None)

    let onlyB lis =
        lis |> List.choose (function
                            | (B _) as b -> Some b
                            | _ -> None)
    let lis = [
        A 1
        A 22
        A 333
        B ""
        B "123"
    ]

    lis |> onlyA |> List.length |> printfn "%d"

您可以进行模式匹配,然后丢弃数据,为过滤器创建一个函数。

type T =
| A of int
| B of string
| C of float

[A 3;A 1;B "foo";B "bar";C 3.1; C 4.6]
|> List.filter (fun x -> 
    match x with
    | A _ -> true
    | B _ -> false
    | C _ -> false
)
|> List.length

但总的来说,我会假设您在模块中创建了一个谓词函数。

let isA x =
    match x with
    | A _ -> true
    | _   -> false

如果你有这些功能,你可以写

[A 3;A 1;B "foo";B "bar";C 3.1; C 4.6]
|> List.filter isA
|> List.length

暂无
暂无

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

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