【问题标题】:Unpacking a first-class module constrained by a type variable解压受类型变量约束的一流模块
【发布时间】:2019-10-11 13:50:48
【问题描述】:

我正在尝试编写一个基本上如下所示的函数:

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

也就是说,一个接受任何类型值的函数,以及一个包含一个或多个可以对该值进行操作的函数的关联模块。不幸的是,上面的代码会让编译器抱怨

这个打包模块的类型包含变量

但是,我发现如果我将它包装在 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 函数,因为它除了帮助编译器出来。这可能吗?

完整示例/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,因为我需要用不同的存在参数对模块进行参数化,这样我就可以将不同类型的模块放在一个列表中。但为简单起见,我在上面的第一个示例中省略了这一点。

【问题讨论】:

    标签: compiler-errors ocaml parametric-polymorphism first-class-modules


    【解决方案1】:

    对于一流的模块(如任何本地模块),您应该使用本地抽象类型而不是显式的多态注释:

    let f (type a) (value:a) (module M: M with type t = a) = M.doStuff value
    

    工作得很好。

    【讨论】:

    • 嗯,确实如此。我确信我试过了,只是将模块包装在 GADT 中,但那肯定是为了别的东西。或者我只是做错了。对于本地抽象类型的工作原理,我仍然没有很好的直觉。无论如何,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    相关资源
    最近更新 更多