type foo = A of int * int | B of (int * int)
int * int
和(int * int)
之间有什么区别?我看到的唯一区别是模式匹配:OCaml中的int * int vs(int * int)和类型
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
它只是一个语法糖吗?你如何选择使用哪一个?这两种形式之间有什么表现差异?
type foo = A of int * int | B of (int * int)
int * int
和(int * int)
之间有什么区别?我看到的唯一区别是模式匹配:OCaml中的int * int vs(int * int)和类型
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
它只是一个语法糖吗?你如何选择使用哪一个?这两种形式之间有什么表现差异?
是的,有一个性能差异:
在存储器A (23, 42)
将包含标签标识它作为一个A
和两个整数23与42 B (23, 42)
将包含标签标识它作为一个B
和指向包含整数23
和42
的元组。因此,在创建B
时会有一个额外的内存分配,并且在访问B
内部的各个值时会有一个额外的间接级别。因此,如果您实际上并未将构造函数参数用作元组,则使用A
将比使用B
花费更少的开销。
在另一方面你test_foo
功能将创建一个新的记录每次调用与A
值的时间,但是当它被称为一个B
值将简单的返回已经存在于内存中的元组。因此test_foo
对于B
比A
更便宜。因此,如果您将构造函数的参数用作元组,并且您将多次使用相同的值,则使用B
将会更便宜。
所以如果你打算使用构造函数参数作为元组,那么使用构造函数来获取元组是有意义的,因为你可以通过使用少量代码的模式匹配来获得元组,并且因为它可以避免必须多次创建来自相同值的元组。在所有其他情况下,不使用元组更好,因为它涉及较少的内存分配和较少的间接。
它们是两种不同的类型。该语法的解释在*
运算符处不明确。它可被还原成以下形式:
int * int
与
type
关键字相关联
type x = Y * Z
其中*
是在构造了一个元组操作者的能力使用
默认优先级将其转换为前者。通过围绕(int * int)
放置括号,可以覆盖默认优先级并强制执行后面的解释。
如前所述,A
的构造函数需要两个int
,而B
的构造函数需要一个有序对。
所以你可以写
let bar = A (1, 2)
或
let bar = B (1, 2)
或
let bar = (1, 2)
let baz = B bar
,但你不能写
let bar = (1, 2)
let baz = A bar
此外,在你的模式匹配,你仍然可以B的内容相匹配的两个int,但不能A的内容相匹配的绑定到一个有序对
let test_foo = function
| A a -> a (* wrong *)
| B (f, s) -> (f, s) (* ok *)
这是棘手的事情在一个价值OCaml语法 - 即使它看起来像使用元组数据类型(A of int * int
)声明构造函数,并且即使在使用构造函数时,它看起来像是给它一个元组(A (2,3)
),但实际上并非如此发生什么事。
如果实际构造一个元组值并尝试将其传递给构造函数,它将不会编译 - let x = (2,3) in A x
。相反,构造函数定义中的*
和构造函数use表达式中的(,)
只是多个参数的构造函数的语法。语法模仿具有元组参数的构造函数,但实际上是分开的。如果你想用一个元组参数实际构造一个构造函数,额外的括号是必须的。
很好的问题。 – didierc 2013-02-11 20:33:52