OCaml和类型中的int * int vs(int * int)

时间:2013-02-11 18:51:40

标签: ocaml

type foo = A of int * int | B of (int * int)

int * int(int * int)之间有什么区别?我看到的唯一区别是模式匹配:

let test_foo = function
  | A (f, s) -> (f, s)
  | B b -> b

它只是一种语法糖吗?你如何选择使用哪一个?这两种形式之间是否有任何性能差异?

4 个答案:

答案 0 :(得分:7)

是的,存在性能差异:

在内存中A (23, 42)将包含一个标记为A的标记,以及两个整数23和42. B (23, 42)将包含一个标记为B的标记,指向包含整数2342的元组的指针。因此,在访问B内的单个值时,在创建B和一个额外的间接级别时,将会有一个额外的内存分配。因此,如果您实际上没有将构造函数参数用作元组,则使用A将比使用B所需的开销更少。

另一方面,每次使用test_foo值调用时,A函数都会创建一个新元组,但是当使用B值调用它时,它将只返回已经存在于内存中的元组。因此test_fooB的操作比对A更便宜。B。因此,如果您将构造函数的参数用作元组,并且您将对同一值使用多次,则使用{{1}}会更便宜。

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

答案 1 :(得分: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 *)

答案 2 :(得分:0)

它们是两种不同的类型。 *运算符对此语法的解释不明确。它可以简化为:

type x = Y * Z其中'*'与OCaml中的type关键字相关联 要么 int * int其中*用于构造元组的运算符的容量

默认优先级将其带到前者。通过在(int * int)周围加上一个括号,可以覆盖默认的优先级,并强制执行后一种解释。

答案 3 :(得分:0)

这是OCaml语法中的一个棘手问题 - 尽管看起来你正在声明一个带有元组数据类型(A of int * int)的构造函数,即使你使用构造函数,它看起来像你给它一个元组(A (2,3)),实际上并不是发生了什么。

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