避免记录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
类型。您可能会发现以下 也很有用。
假设我想要多态函数,在模块中。
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
类型。您可能会发现以下