转换受歧视工会的特定成员列表的规范方法是什么

What is the canonical way to transform a list of a specific member of a discriminated unions

我有一个 DU 的特定成员的列表,在我为这个成员过滤了另一个列表后我想转换它。

type FooBar = 
     | Foo of int
     | Bar of int

type FooBarWrapper = FooWrapper of FooBar

let fbs = [Foo(1); Bar(2); Foo(3); Bar(4)]

let onlyFoos x = 
    match x with
        | Foo x -> true
        | _ -> false

let foos = fbs |> List.filter onlyFoos

let fooValues (Foo x) = x + 1

let result = foos |> List.map fooValues;;

现在这给了我

的不完整模式匹配
let fooValues (Foo x) = x + 1
               ^^^^^

因为我不匹配 Bars - 但是 - 在那个特定的时间点我知道列表只包含 Foos。

唯一的办法就是像这样重写fooValues

let fooValues x = 
    match x with
        | Foo x -> x + 1
        | _ -> failwith "Aint No Foo!"

啊!现在我必须再次进行模式匹配,即使我绝对知道这里不会有任何条。

那么 best/syntactically 在 F# 中实现它的最令人愉快的方法是什么?

附带说明:Haskell 是否有同样的问题?

我认为这不是问题,而是 DU 的设计方式,是的,Haskell 也是如此。否则你可以使用对象和子类型。

但具体针对您提供的示例代码,稍微更改一下设计怎么样?

let onlyFoos x = 
    match x with
        | Foo x -> Some x
        | _ -> None

let foos = fbs |> List.choose onlyFoos

let fooValues x = x + 1
let result = foos |> List.map (Foo << fooValues)

我们的想法是不将 DU 标签与数据一起存储,而是单独存储数据。否则 Tag 将是多余的,因为您知道所有元素都将具有相同的 Tag。稍后,当您再次混合它们时,您可以轻松地重新标记它们。