高级模式匹配
以下是一些有用的额外模式形式:
p1 | ... | pn:一个“或”模式;如果与任何一个单独模式pi匹配成功,则匹配成功,这些模式按从左到右的顺序尝试。所有模式必须绑定相同的变量。(p : t):带有显式类型注释的模式。c:在这里,c表示任何常量,如整数字面值、字符串字面值和布尔值。'ch1'..'ch2':在这里,ch表示一个字符字面量。例如,'A'..'Z'匹配任何大写字母。p when e:仅当e评估为true时,才匹配p。
您可以在手册中阅读有关所有图案形式的信息。
使用 Let 进行模式匹配
到目前为止,我们一直在使用的 let 表达式的语法实际上是 OCaml 允许的完整语法的一个特例。该语法是:
let p = e1 in e2
也就是说,绑定的左侧实际上可能是一个模式,而不仅仅是一个标识符。当然,变量标识符在我们的有效模式列表中,这就是为什么我们迄今为止学习的语法只是一个特例。
鉴于这种语法,我们重新审视 let 表达式的语义。
动态语义学
评估 let p = e1 in e2
- 评估
e1的值为v1 - 匹配
v1与模式p。如果不匹配,则引发异常Match_failure。否则,如果匹配,则产生一组绑定 。 - 将
e2中的绑定b替换为新表达式e2'。 - 评估
e2'的值为v2 - 评估
let表达式的结果是v2。
静态语义
- 如果所有以下条件成立,则
(let p = e1 in e2) : t2:e1 : t1p中的模式变量为x1..xn- 在假设对于
1..n中的所有i都成立xi : ti的情况下,e2 : t2
让我们来看一下定义
与以往一样,let 定义可以被理解为一个 let 表达式,其主体尚未给出。因此,它们的语法可以泛化为
let p = e
它们的语义与之前的 let 表达式的语义一致。
使用函数进行模式匹配
到目前为止,我们一直在使用的函数语法也是 OCaml 允许的完整语法的一个特例。这种语法是:
let f p1 ... pn = e1 in e2 (* function as part of let expression *)
let f p1 ... pn = e (* function definition at toplevel *)
fun p1 ... pn -> e (* anonymous function *)
我们需要关心的真正原始的句法形式是 fun p -> e 。让我们重新审视匿名函数的语义及其在该形式下的应用;其他形式的变化源自以下内容:
静态语义
- 设
x1..xn为出现在p中的模式变量。如果假设x1 : t1和x2 : t2和…和xn : tn,我们可以得出p : t和e :u的结论,则fun p -> e : t -> u。 - 应用程序的类型检查规则保持不变。
动态语义
- 匿名函数的评估规则保持不变。
- 评估
e0 e1- 将
e0评估为匿名函数fun p -> e,并将e1评估为值v1 - 匹配
v1与模式p。如果不匹配,则引发异常Match_failure。否则,如果匹配,则产生一组绑定b。 - 将
e中的绑定b替换为新表达式e'。 - 评估
e'的值为v,这是评估e0 e1的结果。
- 将
模式匹配示例
以下是获取宝可梦生命值的几种方法:
(* Pokemon types *)
type ptype = TNormal | TFire | TWater
(* A record to represent Pokemon *)
type mon = { name : string; hp : int; ptype : ptype }
(* OK *)
let get_hp m = match m with { name = n; hp = h; ptype = t } -> h
(* better *)
let get_hp m = match m with { name = _; hp = h; ptype = _ } -> h
(* better *)
let get_hp m = match m with { name; hp; ptype } -> hp
(* better *)
let get_hp m = match m with { hp } -> hp
(* best *)
let get_hp m = m.hp
type ptype = TNormal | TFire | TWater
type mon = { name : string; hp : int; ptype : ptype; }
val get_hp : mon -> int = <fun>
val get_hp : mon -> int = <fun>
val get_hp : mon -> int = <fun>
val get_hp : mon -> int = <fun>
val get_hp : mon -> int = <fun>
这是如何获取一对中的第一个和第二个组件:
let fst (x, _) = x
let snd (_, y) = y
val fst : 'a * 'b -> 'a = <fun>
val snd : 'a * 'b -> 'b = <fun>
fst 和 snd 实际上已经在标准库中为您定义好了。
最后,以下是获取三元组的第三个组件的几种方法:
(* OK *)
let thrd t = match t with x, y, z -> z
(* good *)
let thrd t =
let x, y, z = t in
z
(* better *)
let thrd t =
let _, _, z = t in
z
(* best *)
let thrd (_, _, z) = z
val thrd : 'a * 'b * 'c -> 'c = <fun>
val thrd : 'a * 'b * 'c -> 'c = <fun>
val thrd : 'a * 'b * 'c -> 'c = <fun>
val thrd : 'a * 'b * 'c -> 'c = <fun>
标准库没有为三元组、四元组等定义任何函数。