我有一个功能:
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语句匹配我想要的方式?
答案 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。