参数多态模块

Parametrically polymorphic modules

这是 monad 的简单 OCaml 模块类型:

module type Monad = sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
end

我可以用任何特定的 monad 实例化它,例如 reader 某种类型的 monad r:

module Reader_monad : Monad = struct
  type 'a t = r -> 'a
  let return a = fun _ -> a
  let bind o f = fun x -> f (o x) x
end

而且我可以通过使用仿函数在类型 r 上对其进行参数化:

module type Readable = sig type r end
module Reader (R : Readable) : Monad = struct
  type 'a t = R.r -> 'a
  let return a = fun _ -> a
  let bind o f = fun x -> f (o x) x
end

但是,后一种方法要求我为不同类型实例化仿函数的不同实例 r。有什么方法可以定义 Monad 类型的“参数多态”模块,它可以提供像 return : 'a -> ('r -> 'a) 这样的参数多态函数?

我认为使用“单子家族”的单独模块类型或多或少可以获得我想要的东西:

module type Monad_family = sig
  type ('c, 'a) t
  val return : 'a -> ('c, 'a) t
  val bind : ('c, 'a) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t
end

module Reader_family : Monad_family = struct
  type ('c, 'a) t = 'c -> 'a
  let return a = fun _ -> a
  let bind o f = fun x -> f (o x) x
end

但是如果我有大量关于 monad 的一般事实库,这将需要手动修改它以使用系列。然后一些 monad 由一对类型参数化(尽管我认为这可以由产品类型编码),等等。所以我宁愿避免这样做。

如果这不能直接实现,是否至少有一种方法可以在参数化多态函数中本地实例化模块 Reader?我以为我可以用 first-class 模块做到这一点,但我天真的尝试

let module M = Reader(val (module struct type r = int end) : Readable) in M.return "hello";;

产生错误信息

Error: This expression has type string M.t
       but an expression was expected of type 'a
       The type constructor M.t would escape its scope

我不明白。类型 M.t 不等于 int -> string 吗?

我认为这是与 相同的问题,其中模块 M 的寿命不够长。如果您改写

# module M = Reader(struct type r = int end);;
# M.return "hello";;
- : string M.t = <fun>

这样就可以了。

另外,Reader 仿函数失去了一些您可能想要的类型等式。您可以通过这样定义来恢复它们:

module Reader (R : Readable) : Monad with type 'a t = R.r -> 'a = struct
  type 'a t = R.r -> 'a
  let return a = fun _ -> a
  let bind o f = fun x -> f (o x) x
end