10
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

4 回答 4

7

是的,存在性能差异:

在内存A (23, 42)中将包含一个将其标识为 a 的标签A和两个整数 23 和 42。B (23, 42)将包含一个将其标识为 a 的标签B和一个指向包含整数23和的元组的指针42。因此,在创建 a 时将有一个额外的内存分配,B而在访问 a 中的各个值时会有一个额外的间接级别B。因此,在您实际上不将构造函数参数用作元组的情况下, usingA将比 using 涉及更少的开销B

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

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

于 2013-02-11T19:11:55.883 回答
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 *)
于 2013-02-11T20:29:21.007 回答
0

它们是两种不同的类型。这种语法的解释在*运算符处是模棱两可的。它可以简化为以下形式:

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

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

于 2013-02-11T19:32:08.710 回答
0

这是 OCaml 语法中的棘手问题之一——即使看起来您正在声明一个具有元组数据类型 ( A of int * int) 的构造函数,并且即使当您使用构造函数时,看起来您正在给它一个元组 ( A (2,3)),这实际上并不是正在发生的事情。

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

于 2013-02-12T02:23:24.777 回答