OCaml:将变量与元组的解构元素匹配的模式吗?

时间:2020-07-30 03:59:41

标签: pattern-matching ocaml destructuring

我有一个功能:

let map_plug (pairs : (char * char) list) input =
  let rec plug_aux pairs input = 
    match pairs with
    | [] -> 'A'
    | h :: t -> let first, second = h in
      match input with
      | first -> second
      | second -> first
      | _ -> plug_aux t input
  in plug_aux pairs input

...,其中包含一个字符对列表和一个输入字符。

我关注的代码在这里:

let first, second = h in
      match input with
      | first -> second
      | second -> first
      | _ -> plug_aux t input

OCaml告诉我,第一种情况是无可辩驳的,其他情况没有使用。我发现这种行为令人困惑,因为我想破坏元组并绑定其元素,然后将变量与这些元素匹配;它似乎不起作用。

我举了一个简单的例子:

let x, y = (3, 4) in 
  match 4 with
  | x -> 7
  | y -> 8;;
Line 4, characters 2-3:
Warning 11: this match case is unused.

同样在Rust中进行测试,也会产生相同的错误。我意识到此时OCaml必须相信y只是新绑定的阴影名称,因此可以将所有内容与之匹配。

但是我也知道,使用if语句可以使我处理解构元组的绑定元素,而不是声明任何新变量。是否可以使用match语句匹配我想要的方式?

3 个答案:

答案 0 :(得分:1)

OCaml中的模式本质上是结构化常量,其中常量的组成部分可以指定为变量名。名称绑定到匹配表达式的相应部分。

match语句不会将值与任意表达式匹配,而只会匹配结构化常量(在上述意义上)。

因此,该匹配项:

match input with
| first -> ...

将始终成功,并将first绑定为与input相同的值。无论名称first之前是否存在绑定,都是如此。

这样的比赛:

match input with
| first when first = fst -> code ()
| _ -> other_code ()

本质上是一种编写if语句的复杂方式:

if input = fst then
    code ()
else
    other_code ()

我认为if语句更加清晰。一方面,它没有引入不相关的名称,例如first

答案 1 :(得分:0)

在进行调查的同时,我意识到在这种情况下进行范围界定(乍一看)有些不直观。一种可能的解决方案:

let map_plug (pairs : (char * char) list) input =
  let rec plug_aux pairs input = 
    match pairs with
    | [] -> 'A'
    | h :: t -> let fst, snd = h in
      match input with
      | first when first = fst -> snd
      | second when second = snd -> fst
      | _ -> plug_aux t input
  in plug_aux pairs input

正如您所看到的,我放置了模式防护(本质上是if语句)来产生仍然使用match语句的类似功能。这让我明白,模式卫士的范围实际上是来自match语句外部的绑定,而模式本身中的任何内容都不重要,因为我试图在运行时与变量而不是模式进行匹配。 / p>

回想起来,这是一个非常基本的概念,但是令我惊讶的是,实际上,这是动态模式匹配的一种形式。相关的SO帖子-Pattern matching a variable in OCaml?-对此进行了讨论。

答案 2 :(得分:0)

听起来您对Ocaml模式的功能感到困惑。

  • 他们可以解构数据并检查使用哪种总和类型的变体。

  • 他们还可以比较反对文字的数据。

但是他们不能将变量与另一个变量进行比较,除非使用when防护。

基本上,匹配是为了给事物起名字,而不是检查是否相等

使用示例:

match x with 
| 1 -> print_string "one" (* you can match x with 1 because 1 is a constant literal*)
| 2 -> print_string "two"
| y -> print_int y (* here y is a *new name* that is given x’s value*)
let y = 3 in 
match x with 
| 1 -> print_string "one" )
| 2 -> print_string "two"
| y -> print_int y (* here y is *still a new name* that is given x’s value. 
It shadows the previous y value ! 
It does not check that x = 3, and will always be executed when x is not 1 or 2*)

如果您要检查匹配项中x与y的值相同,则必须编写类似的内容

let y = 3 in 
match x with 
| 1 -> print_string "one"
| 2 -> print_string "two"
| z when z = y -> print_string "three"
| z -> print_int z

when后卫允许您为比赛添加条件。 最后一个条件将习惯上写成:

let y = 3 in 
match x with 
| 1 -> print_string "one"
| 2 -> print_string "two"
| _ when x = y -> print_string "three"
| _ -> print_int x

因为您实际上并不需要在这里将x重命名为z。

相关问题