转换受歧视联盟的特定成员名单的规范方法是什么?

rob*_*kuz 2 f# pattern-matching discriminated-union

我有一个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;;
Run Code Online (Sandbox Code Playgroud)

现在这给了我一个不完整的模式匹配

let fooValues (Foo x) = x + 1
               ^^^^^
Run Code Online (Sandbox Code Playgroud)

因为我不匹配酒吧 - 但随后 - 在那个特定的时间点我知道该列表只包含Foos.

唯一的方法是fooValues像这样重写

let fooValues x = 
    match x with
        | Foo x -> x + 1
        | _ -> failwith "Aint No Foo!"
Run Code Online (Sandbox Code Playgroud)

哎呀!现在我必须再次模式匹配,即使我绝对知道这里不会有任何酒吧.

那么在F#中实现这一点的最佳/语法最令人满意的方法是什么?

并且作为旁注:Haskell有同样的问题吗?

Gus*_*Gus 6

我不认为这是一个问题,它更像是设计的方式,是的,同样适用于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)
Run Code Online (Sandbox Code Playgroud)

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