使用只有一个元组值的变体类型构造函数

时间:2012-03-19 17:14:13

标签: constructor ocaml

# type foo = Foo of int * int
# let t = (1, 2)
# Foo t
Error: The constructor Foo expects 2 argument(s),
   but is applied here to 1 argument(s)

如果 t 具有合适的类型,我必须Foo (1, 2)如何避免该错误?

2 个答案:

答案 0 :(得分:11)

在我看来,这是OCaml语法的一个令人不安的部分。尽管它看起来很像,但构造函数Foo不需要2元组作为其参数。从语法上讲,它在括号中需要两个值 - 但它们不是元组。所以t的类型错误就是这种情况。做这项工作的方法是:

let (a, b) = t in Foo (a, b)

问题实际上是括号被用于两种不同的东西(或者我声称)。一旦你习惯了这一点,处理就不那么困难了。

编辑:如果您希望构造函数Foo采用单个元组,而不是两个单独的值,您可以像这样定义:

type foo = Foo of (int * int)

然后原始代码的其余部分将起作用。

答案 1 :(得分:5)

请注意,Foo of (a * b)Foo of a * b之间的区别是出于效率原因:Foo of (a * b)有一个参数,它是一个元组,指向堆中两个元素的指针。 Foo of a * b有两个参数直接用标签打包,避免了间接。

这也是为什么,例如,使用关联列表的算法(例如带链接列表桶的Hashtables)有时会定义自己的数据类型而不是重用('a * 'b) list

type ('a, 'b) assoc_list =
  | Nil
  | Cons of 'a * 'b * ('a, 'b) assoc_list

当然,在一般的高级别案例中,这种专业化并不是非常重要(并且可能会阻碍代码重用),但是当您真正需要更严格的控制时能够了解这些技术细节仍然很好过度记忆表示。