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

时间:2015-10-05 20:04:32

标签: f# pattern-matching discriminated-union

在Haskell中,如果我有一个联合类型值列表,如下所示:

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

我可以用一点"技巧"提取匹配某些特定模式的所有结果:

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#中,是否有一些方便的方法来提取(和匹配)所有与列表/序列中的特定模式匹配的值

2 个答案:

答案 0 :(得分:16)

在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']

此功能对于这些情况非常方便。

答案 1 :(得分:12)

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

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

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

F#在列表表达式中没有相同的概念,因此您必须更加详细。在这里,我们只使用for迭代所有项目,然后我们明确使用yield为源列表中的每个Choice1Of2生成一个新值(我们只是跳过其他任何事情。)

根据您正在做的事情,使用List.choose(如Gustavo的答案中所述)可能会更容易。但上面的内容可能是最接近Haskell的理解语法。