OR模式匹配

3

我正在尝试使用OR模式,如这里所述:

let foo = function
    | Some (0, x) when x > 0 | None -> "bar"
    | _ -> "baz"

然而,这样会导致编译错误:

error FS0010:在模式匹配中出现意外符号'|'。应该期望的是'->'或其他标记。

我做错了什么?这与when保护有关吗?

谢谢,一直在找这个。奇怪的是这个问题没有被问得很多。Scala可以更优雅地解决这个问题。 - nawfal
3个回答

7

when保护语句针对单个情况进行判断,不论有多少个模式组合。这些情况需要分开写:

let foo = function
  | Some (0, x) when x > 0 -> "bar"
  | None -> "bar"
  | _ -> "baz"

因此,最好将返回值分解出来,这样可能复杂的表达式就不会重复出现:

let foo value =
  let ret = "bar"
  match value with
  | Some (0, x) when x > 0 -> ret
  | None -> ret
  | _ -> "baz"

使用活动模式是避免这种重复的另一种方式:
let (|Bar|_|) = function
  | Some(0, x) when x > 0 -> Some()
  | None -> Some()
  | _ -> None

let foo = function
  | Bar -> "bar"
  | _ -> "baz"

活动模式也更加简洁,可以让您进行组合构建。 - 7sharp9

2

在这里你需要两个不同的匹配情况,因为这两种情况绑定了不同的变量集合(分别是x和空):

| Some(0, x) when x>0 -> "bar"
| None -> "bar"

2

当你想要保护标签的特定绑定时,可以使用自己的活动模式和& (and) 模式运算符来处理非常复杂的模式:

let (|GreaterThan|_|) lowerLimit n =
    if n > lowerLimit then Some () else None

let (|LesserThan|_|) upperLimit n =
    if n < upperLimit then Some () else None

let (|GreaterOETo|_|) lowerLimit n =
    if n >= lowerLimit then Some () else None

let (|LesserOETo|_|) upperLimit n =
    if n <= upperLimit then Some () else None

let (|InRange|_|) (lowerLimit, upperLimit) n =
    if n >= lowerLimit && n <= upperLimit then Some () else None

let (|Even|Odd|) n =
    if n % 2 = 0 then
        Even (n / 2)
    else
        Odd (n / 2)

type Union =
    | A of int
    | B of int
    | A' of int

let getSpecialCases = function
    | A (Even (x & GreaterThan 4 & LesserOETo 16))
    | A (Odd (x & GreaterThan 0))
    | B (x & LesserOETo 0)
    | A' (Even (x & InRange (5, 16)))
    | A' (Odd (x & GreaterThan 0)) -> Some x
    | _ -> None

当然,您可以编写一个函数来激活模式包装器:
let (|P|_|) pred x =
    if pred x then Some () else None

let ``match`` = function
    | Even (x & pred (fun x -> x >= 7 && x <= 54)) -> Some x
    | _ -> None

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接