【问题标题】:Pattern matching and constructors模式匹配和构造函数
【发布时间】:2012-04-29 21:59:40
【问题描述】:
为什么我写这种模式匹配时会出错:
type t = A of int | B of float
let f = function
| (A i | B f) -> true
| _ -> false
或
let f = function
| A i | B f -> true
| _ -> false
错误:变量 f 必须出现在 this | 的两边模式
let f = function
| (A i | B i) -> true
| _ -> false
或
let f = function
| A i | B i -> true
| _ -> false
错误:此模式匹配浮点类型整数的值
但应有与值匹配的模式
【问题讨论】:
标签:
functional-programming
pattern-matching
ocaml
【解决方案1】:
如果您为多个模式提供一个右侧(如您所做的那样),OCaml 要求模式始终绑定到模式变量。
第一种情况,
match ... with
| A i | B f -> ...
...
模式在它们绑定的变量上不一致:第一个模式绑定到i,而第二个绑定到f。
第二种情况,
match ... with
| A i | B i -> ...
...
模式不同意绑定到其变量的值类型:第一个模式将int 类型的值绑定到i,而第二个模式将float 类型的值绑定到@987654328 @。
这两种模式可以始终绑定到变量的唯一方法是根本不绑定到任何变量:
match ... with
| A _ | B _ -> ...
...
那么完整的例子就变成了
type t = A of int | B of float
let f = function
| A _ | B _ -> true
| _ -> false
(但请注意,模式匹配的最后一个分支是多余的,因为前两个模式已经完全匹配您类型 t 的所有值。因此,我们得到:
let f = function
| A _ | B _ -> true
这当然相当于写let f _ = true。)
【解决方案2】:
在Or 模式(| 模式)中,您无法跟踪您所在的构造函数。因此,您需要绑定相同的变量集才能工作,而不需要引用构造函数。
OCaml 是强类型的;值 i 不能同时具有类型 int 和类型 float。
如果类型t有两个以上的情况,你应该写:
let f = function
| A _ | B _ -> true
| _ -> false
否则:
let f = function
| A _ | B _ -> true
足够了,因为模式匹配已经很详尽了。
我同意Or 模式的限制性很强,但有时当你的函数中有对称情况时它会很有帮助:
type num =
| Int of int
| Float of float
let add s1 s2 =
match s1, s2 with
| Int i1, Int i2 -> Int (i1 + i2)
| Int i, Float f | Float f, Int i -> Float (float i +. f)
| Float f1, Float f2 -> Float (f1 +. f2)