避免记录ocaml中的多态性

Avoiding record for polymorphism in ocaml

假设我想要多态函数,在模块中。

  module type NewHType1 = sig
    type ('a, 'n) t
    type t'
    type ('n, 't) inj = { inj : 'a. ('a, 'n) t -> ('a, ('n, t') happ) app
    type ('n, 't) prj = { prj : 'a. ('a, ('n, t') happ) app -> ('a, 'n) t }

    val inj : ('n, 't) inj
    val prj : ('n, 't) prj
  end

我在语法上真的必须有一个多态记录类型,有一个多余的记录字段吗?

(我依稀记得有人提到对象是为了避免这种额外的噪音(?))

您可以使用 GADT 对存在性进行本地编码。例如,这就是你如何用 GADT 编码 higher-kinded polymorphism

type ('p, 'f) app = ..

module Newtype1 (T : sig type 'a t end) () : sig
  type 'a s = 'a T.t
  type t

  val inj : 'a s -> ('a, t) app
  val prj : ('a, t) app -> 'a s
end = struct
  type 'a s = 'a T.t
  type t
  type (_,_) app += App : 'a s -> ('a, t) app
  let inj v = App v
  let prj (App v) = v
end

module Newtype2 (T : sig type ('a,'b) t end) () : sig
  type ('a, 'b) s = ('a, 'b) T.t
  type t

  val inj : ('a, 'b) s -> ('a, ('b, t) app) app
  val prj : ('a, ('b, t) app) app -> ('a, 'b) s
end = struct
  type ('a,'b) s = ('a,'b) T.t
  type t
  type (_,_) app += App : ('a,'b) s -> ('a, ('b,t) app) app
  let inj v = App v
  let prj (App v) = v
end

附带说明一下,您不需要在签名中使用记录或任何其他内容来指定类型变量是多态的,因为它已经是多态的。也就是说,您可以简单地描述您的签名,

module type NewHType1 = sig
  type ('a, 'n) t
  type t'
  val inj : ('a, 'n) t -> ('a, ('n, t') happ) app
  val prj : ('a, ('n, t') happ) app -> ('a, 'n) t
end

这是因为在值规范中(在模块类型中)多态变量表示多态类型,这与类型约束不同,类型约束用于值定义,其中类型变量仅表示可以具有基础类型的变量,所以如果你想防止它与地面类型统一,你必须添加一个类型注释,例如,

module NewHType1 : sig
  type ('a, 'n) t
  type t'
  val inj : ('a, 'n) t -> ('a, ('n, t') happ) app
  val prj : ('a, ('n, t') happ) app -> ('a, 'n) t
end = struct
  type ('a,'n) t and t'
  let inj : 'a. ('a, 'n) t -> ('a, ('n, t') happ) app = fun _ -> assert false
  let prj : 'a. ('a, ('n, t') happ) app -> ('a, 'n) t = fun _ -> assert false
end

总而言之,'a. 'a -> 'a 类型约束生成多态 'a -> 'a 类型。您可能会发现以下 也很有用。