我们说我写这段代码:
# type t = A of int * int
let f = function A (i1, i2) -> print_int i1;;
type t = A of int * int
val f : t -> unit = <fun>
完美,它有效。
现在,让我们说我有这个奇妙的功能:
# let print_couple (i1, i2) = print_int i1; print_int i2;;
val print_couple : int * int -> unit = <fun>
所以,正如您所期望的那样,我想写下以下内容
# let f = function A (_ as c) -> print_couple c;;
好吧,我不能
Error: The constructor A expects 2 argument(s),
but is applied here to 1 argument(s)
我想知道,是因为_
还是括号(我认真地对此表示怀疑,但我想要详尽无遗)?
# let f = function A _ -> failwith "Fight me"
let g = function A (_) -> failwith "1o1";;
val f : t -> 'a = <fun>
val g : t -> 'a = <fun>
不,它不是......
哦,也许我必须展示编译器我知道我有两个参数:
# let f = function A ((_, _) as c) -> print_couple c;;
Error: The constructor A expects 2 argument(s),
but is applied here to 1 argument(s)
但......如果我写
# let f = function A (_, _) -> failwith "Puppey style";;
有效。那么,为什么,因为编译器知道我期待一对夫妇,我甚至试图把它给他,它一直在失败?是不是通过写A (_ as c)
来命名,无论如何,第一个参数?这很奇怪,不是吗?
我的意思是,如果我写
# let rec f = function
| [] -> ()
| hd :: tl -> print_couple hd; f tl;;
val f : (int * int) list -> unit = <fun>
编译器不会打扰我这个列表是关联列表还是整数列表?那么从我这里得到同样的行为是很奇怪的
# match a with
| A c | A (_ as c) | A ((_, _) as c) -> ()
答案 0 :(得分:3)
严格地说,当您声明A of int * int
时,A
需要两个int
个参数,而不是一对int
组成的参数。 _
只是一个参数的占位符,因此您在编写A (_ as c)
(或A _
)时会看到错误消息。没有办法(没有使用黑魔法,我不会在这里描述)以某种方式将A
的两个参数隐含地转换成一对:你必须诉诸match x with A (x,y) -> x,y
。
另一种方法是声明构造函数,使其成为一对,如下面的代码所示。请注意,这样效率较低(您需要两个间接访问A
的参数,一个用于检索其中一个,另一个用于检索其组件):
type t = A of (int * int)
let print_couple (i1, i2) = print_int i1; print_int i2
let f = function A c -> print_couple c
答案 1 :(得分:2)
这是OCaml的一个怪癖,像A
定义的构造函数在语法上看起来像一对,但不是一对。
# type t = A of int * int;;
type t = A of int * int
# A (3, 4);;
- : t = A (3, 4)
# let z = (3, 4) in A z;;
Error: The constructor A expects 2 argument(s),
but is applied here to 1 argument(s)
如果将构造函数定义为实际使用一对,则可以提供一对:
# type u = B of (int * int);;
type u = B of (int * int)
# B (3, 4);;
- : u = B (3, 4)
# let z = (3, 4) in B z;;
- : u = B (3, 4)
这有点令人困惑,但它只是OCaml的工作方式。您需要为A
等构造函数提供专门用括号的参数。
在与_
匹配时,您不需要提供明确的括号,这也有点令人惊讶:
# let A _ = A (4, 5);;
#
(当然,这仅作为更大模式的一部分有用。)