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

Ric*_*rdo 7 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)
Run Code Online (Sandbox Code Playgroud)

它是如何,我必须这样做Foo (1, 2),以避免错误甚至牛逼有合适的类型?

Jef*_*eld 12

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

let (a, b) = t in Foo (a, b)
Run Code Online (Sandbox Code Playgroud)

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

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

type foo = Foo of (int * int)
Run Code Online (Sandbox Code Playgroud)

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

  • @Ricardo,Jeffrey:把`(a,b)`想象成一个空名的构造函数. (2认同)

gas*_*che 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
Run Code Online (Sandbox Code Playgroud)

当然,在一般的高级别情况下,这种专业化并不是非常重要(并且可能会阻碍代码重用),但是当您真正需要更严格地控​​制内存表示时,能够了解这些技术细节仍然很好.