如何在 `for .. in` 中对联合构造函数进行模式匹配

How to pattern match on union constructors in `for .. in`

在 Haskell 中,如果我有一个像这样的联合类型值列表:

example :: [Either Int Char]
example = [Left 3, Right 'b', Left 6, Left 9, Right 'c']

我可以使用一些 "trick" 来提取所有匹配特定模式的结果:

lefts :: [Int]
lefts = [l | Left l <- example]

但是,如果我尝试将其转换为 F#,则会出现错误:

let lefts = [for Choice1Of2 l in example -> l]
                 ~~~~~~~~~~~~
Incomplete pattern matches on this expression. (...)

这很有意义(它甚至可能比像 Haskell 那样默默地忽略 Right 值更好!),但是 在 F# 中,是否有一些方便的在 list/sequence?

中提取(并匹配)与特定模式匹配的所有值的方法

我认为使用 F# 列表表达式最接近的事情是这样的:

let lefts example = 
  [ for e in example do
      match e with Choice1Of2 l -> yield l | _ -> () ]

如果我正确理解 Haskell 代码,| 之后的部分不仅用作提取器,还用作过滤器 - 隐式跳过所有与模式不匹配的东西.

F#在列表表达式中没有同类的概念,所以你必须更加冗长。在这里,我们只是使用 for 遍历 all 项,然后我们明确地使用 yield 为源列表中的每个 Choice1Of2 生成一个新值(我们只是跳过其他任何内容)。

根据您的操作,使用 List.choose(如 Gustavo 的回答中所述)可能更容易。但上面的内容可能最接近 Haskell 的 comprehension 语法。

在 F# 中,如果您不匹配所有情况,您将在所有情况下收到警告。

所以你可以在表达式中写出两种情况的匹配,但是为了你的例子而不是理解,我会使用函数 List.choose:

let example = [Choice2Of2 3; Choice1Of2 'b'; Choice2Of2 6; Choice2Of2 9; Choice1Of2 'c']
List.choose (function (Choice1Of2 x) -> Some x | _ -> None) example
// val it : char list = ['b'; 'c']

这个函数对这些情况很方便。