`(a,b)` 与 ocaml 中的 `(a*b)`
`(a,b)` versus `(a*b)` in ocaml
好像只有a * b
能装进_
,只有(a,b)
能装进(a,_)
。
我可以想象 a*b
是具有组件 a
和 b
的内部产品的正确类型,而 (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个参数中存储左右类型。
好像只有a * b
能装进_
,只有(a,b)
能装进(a,_)
。
我可以想象 a*b
是具有组件 a
和 b
的内部产品的正确类型,而 (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个参数中存储左右类型。