2013-02-11 44 views
8
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 

它只是一个语法糖吗?你如何选择使用哪一个?这两种形式之间有什么表现差异?

+0

很好的问题。 – didierc 2013-02-11 20:33:52

回答

7

是的,有一个性能差异:

在存储器A (23, 42)将包含标签标识它作为一个A和两个整数23与42 B (23, 42)将包含标签标识它作为一个B和指向包含整数2342的元组。因此,在创建B时会有一个额外的内存分配,并且在访问B内部的各个值时会有一个额外的间接级别。因此,如果您实际上并未将构造函数参数用作元组,则使用A将比使用B花费更少的开销。

在另一方面你test_foo功能将创建一个新的记录每次调用与A值的时间,但是当它被称为一个B值将简单的返回已经存在于内存中的元组。因此test_foo对于BA更便宜。因此,如果您将构造函数的参数用作元组,并且您将多次使用相同的值,则使用B将会更便宜。

所以如果你打算使用构造函数参数作为元组,那么使用构造函数来获取元组是有意义的,因为你可以通过使用少量代码的模式匹配来获得元组,并且因为它可以避免必须多次创建来自相同值的元组。在所有其他情况下,不使用元组更好,因为它涉及较少的内存分配和较少的间接。

+0

所以,没有新的元组创建就不可能从'A'中提取信息,对吧? – Stas 2013-02-11 19:28:08

+0

@Stas这取决于你的意思是“提取信息”。无法创建包含“A”数据的元组而不创建新的元组。但是,无需创建元组就可以用'A'的数据做一些事情。例如,像'match foo with A(x,y) - > x + y'这样的东西不会创建一个元组,并且会比使用'B'的等价代码快。 – sepp2k 2013-02-11 19:32:11

+0

我明白了。谢谢!我认为元组需要匹配'A(x,y)'。 – Stas 2013-02-11 19:52:37

0

它们是两种不同的类型。该语法的解释在*运算符处不明确。它可被还原成以下形式:

,其中“*”是OCaml中 或 int * inttype关键字相关联

type x = Y * Z其中*是在构造了一个元组操作者的能力使用

默认优先级将其转换为前者。通过围绕(int * int)放置括号,可以覆盖默认优先级并强制执行后面的解释。

2

如前所述,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 *) 
0

这是棘手的事情在一个价值OCaml语法 - 即使它看起来像使用元组数据类型(A of int * int)声明构造函数,并且即使在使用构造函数时,它看起来像是给它一个元组(A (2,3)),但实际上并非如此发生什么事。

如果实际构造一个元组值并尝试将其传递给构造函数,它将不会编译 - let x = (2,3) in A x。相反,构造函数定义中的*和构造函数use表达式中的(,)只是多个参数的构造函数的语法。语法模仿具有元组参数的构造函数,但实际上是分开的。如果你想用一个元组参数实际构造一个构造函数,额外的括号是必须的。