`(a,b)` 与 ocaml 中的 `(a*b)`

`(a,b)` versus `(a*b)` in ocaml

好像只有a * b能装进_,只有(a,b)能装进(a,_)

我可以想象 a*b 是具有组件 ab 的内部产品的正确类型,而 (a,b) 是类型 [=17] 的外部产品=] 并输入 b(只是猜测)

但是有区分这两者的例子吗?

type zero = Z : zero
type 'a succ = S : 'a succ

type _ ptree1 =
  | Leaf : 'a -> ('a * zero) ptree1
  | Node : (('a * 'n) ptree1 * ('a * 'n) ptree1) -> ('a * 'n succ) ptree1

type (_, _) ptree =
  | Leaf : 'a -> ('a, zero) ptree
  | Node : (('a, 'n) ptree * ('a, 'n) ptree) -> ('a, 'n succ) ptree

(* bad
type ('a * _) ptree =
  | Leaf : 'a -> ('a, zero) ptree
  | Node : (('a, 'n) ptree * ('a, 'n) ptree) -> ('a, 'n succ) ptree
 *)
let rec last1 : type n a. (a * n) ptree1 -> a = function
  | Leaf x      -> x
  | Node (_, t) -> last1 t

let rec last : type n a. (a, n) ptree -> a = function
  | Leaf x      -> x
  | Node (_, t) -> last t

类型构造函数在 OCaml 中有一个元数。 例如,在

type ('a,'b) either =
 | Left of 'a
 | Right of 'b

类型构造函数 either 的元数为 2。 ('a,'b) either 表示应用于两个参数 'a'b 的类型构造函数 either。形式 ('a,'b) 本身在语言中不存在。

但是,可以将元数为 n 的类型构造函数编码为元数为 1 的类型构造函数,但仅限于将 n 元组类型作为参数。 通常,这意味着将 either 重写为

type 'p either2 =
 | Left2 of 'a
 | Right2 of 'b
constraint 'p = 'a * 'b

let translation: type a b. (a*b) either2 -> (a,b) either = function
| Left2 x -> Left x
| Right2 x -> Right x

这里,either2是一个元数的类型构造函数,但是参数必须是二元组类型。

这相当于在类型级别将类型 'a -> 'b -> 'c 的函数转换为类型 'a * 'b -> 'c 的函数。 另一种观点是,类型级应用程序被编写为函数应用程序 ('a,'b) either 将被编写为 either 'a 'b('a * 'b) either2 将变为 either2 ('a * 'b).

如果没有 GADT,这种编码需要使用显式 constraint,因此它们不会那么频繁。 对于 GADT,由于 GADT 的定义可以自由构建它自己的类型索引,因此这种选择更加明显。例如,可以将 either 的偏心版本定义为

type (_,_,_) either3 =
| Left3: 'a -> ('a list -> _, 'a * unit, _) either3
| Right3: 'a -> ( _ -> 'a array, _, unit * 'a) either3

let translate: type a b. (a list -> b array, a * unit, unit * b) either3 -> (a,b) either =
function
| Left3 x -> Left x
| Right3 x -> Right x

这里,either3是一个元数3的类型构造函数,它在它的第3个参数中存储左右类型。