解压受类型变量约束的 first-class 模块
Unpacking a first-class module constrained by a type variable
我正在尝试编写一个基本如下所示的函数:
module type M = sig
type t
val doStuff : t -> unit
end
let f : 'a. 'a -> (module M with type t = 'a) -> unit
= fun value (module MSomething) -> MSomething.doStuff value
也就是说,一个函数可以接受任何类型的值,以及一个包含一个或多个可以对该值进行操作的函数的关联模块。不幸的是,上面的编译器会抱怨
The type of this packed module contains variables
但是,我发现如果我将它包装在一个 GADT 中,我仍然可以让它工作,1) 使 'a
成为一个存在的,并且 2) 提供一个从另一个参数化类型变量到存在主义:
type 'b gadt =
GADT: ('b -> 'a) * (module M with type t = 'a) -> 'b gadt
let f value (GADT (convert, (module MSomething))) =
MSomething.doStuff (convert value)
GADT 本身并不麻烦1,但我非常想避免使用 convert
函数,因为它不除了帮助编译器之外,它没有任何其他用途。 这可能以某种方式实现吗?
完整 example/MCVE
module type M = sig
type t
val doStuff : t -> unit
end
module MInt = struct
type t = int
let doStuff = print_int
end
let f : 'a. 'a -> (module M with type t = 'a) -> unit
= fun value (module MSomething) -> MSomething.doStuff value
let () = f 42 (module MInt : M with type t = int)
let () = print_newline ()
1 我实际上想要 GADT,因为我需要模块由不同的存在参数化,这样我就可以将不同类型的模块放在一个列表中。但为了简单起见,我在上面的第一个示例中省略了它。
对于第一个 class 模块(就像任何本地模块一样),您应该使用本地抽象类型而不是显式多态注释:
let f (type a) (value:a) (module M: M with type t = a) = M.doStuff value
工作正常。
我正在尝试编写一个基本如下所示的函数:
module type M = sig
type t
val doStuff : t -> unit
end
let f : 'a. 'a -> (module M with type t = 'a) -> unit
= fun value (module MSomething) -> MSomething.doStuff value
也就是说,一个函数可以接受任何类型的值,以及一个包含一个或多个可以对该值进行操作的函数的关联模块。不幸的是,上面的编译器会抱怨
The type of this packed module contains variables
但是,我发现如果我将它包装在一个 GADT 中,我仍然可以让它工作,1) 使 'a
成为一个存在的,并且 2) 提供一个从另一个参数化类型变量到存在主义:
type 'b gadt =
GADT: ('b -> 'a) * (module M with type t = 'a) -> 'b gadt
let f value (GADT (convert, (module MSomething))) =
MSomething.doStuff (convert value)
GADT 本身并不麻烦1,但我非常想避免使用 convert
函数,因为它不除了帮助编译器之外,它没有任何其他用途。 这可能以某种方式实现吗?
完整 example/MCVE
module type M = sig
type t
val doStuff : t -> unit
end
module MInt = struct
type t = int
let doStuff = print_int
end
let f : 'a. 'a -> (module M with type t = 'a) -> unit
= fun value (module MSomething) -> MSomething.doStuff value
let () = f 42 (module MInt : M with type t = int)
let () = print_newline ()
1 我实际上想要 GADT,因为我需要模块由不同的存在参数化,这样我就可以将不同类型的模块放在一个列表中。但为了简单起见,我在上面的第一个示例中省略了它。
对于第一个 class 模块(就像任何本地模块一样),您应该使用本地抽象类型而不是显式多态注释:
let f (type a) (value:a) (module M: M with type t = a) = M.doStuff value
工作正常。