OCaml:更高级的多态性(在模块上抽象?)

OCaml:更高级的多态性(在模块上抽象?),ocaml,monads,higher-kinded-types,Ocaml,Monads,Higher Kinded Types,假设我有一个选项列表: let opts = [Some 1; None; Some 4] 我想将这些转换为列表选项,以便: 如果列表包含None,则结果为None 否则,将收集各种int 对于这种特定的情况,编写这种代码相对简单(使用和Monad模块): 然而,正如问题标题所暗示的,我真的很想抽象类型构造函数,而不是专门研究选项。Core似乎使用了一个函子来提供更高级类型的效果,但我不清楚如何编写要在模块上抽象的函数。在Scala中,我会使用隐式上下文绑定,以要求某些Monad[M[\u

假设我有一个选项列表:

let opts = [Some 1; None; Some 4]
我想将这些转换为列表选项,以便:

  • 如果列表包含
    None
    ,则结果为
    None
  • 否则,将收集各种int
对于这种特定的情况,编写这种代码相对简单(使用和
Monad
模块):

然而,正如问题标题所暗示的,我真的很想抽象类型构造函数,而不是专门研究
选项
。Core似乎使用了一个函子来提供更高级类型的效果,但我不清楚如何编写要在模块上抽象的函数。在Scala中,我会使用隐式上下文绑定,以要求某些
Monad[M[\u]]]
的可用性。我希望没有隐式传递模块的方法,但是如何显式传递呢?换言之,我可以写一些近似的东西吗:

let sequence (module M : Monad.S) foo =
let open M in
let open M.Monad_infix in
  List.fold ~init:(return []) ~f:(fun acc x ->  
    acc >>= fun acc' -> 
    x >>= fun x' -> 
    return (x' :: acc')
    ) foo;;
这是第一类模块可以实现的吗

编辑:好的,所以我实际上并没有想到要尝试使用那个特定的代码,而且它似乎比我预期的更接近于工作!看起来语法实际上是有效的,但我得到了以下结果:

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

错误的第一部分看起来很混乱,因为它们匹配,所以我猜问题出在第二部分——这里的问题是返回类型似乎没有确定吗?我想这取决于传入的模块-这是一个问题吗?有没有办法修复此实现?

首先,这里是代码的自包含版本(使用遗留版本)
列表。折叠(标准库的左
)供没有 核心在手,仍然想尝试编译您的例子

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

let sequence (module M : MonadSig) foo =
  let open M in
  let (>>=) = bind in
  List.fold_left (fun acc x ->  
    acc >>= fun acc' -> 
    x >>= fun x' -> 
    return (x' :: acc')
  ) (return []) foo;;
您得到的错误消息意味着(第一行可能会混淆) 忽略)M.t定义是
M
模块的本地定义,以及 不能逃避它的范围,这将与您正在尝试的内容相关 写作

这是因为您使用的是一流的模块,允许 在模块上抽象,但不具有依赖的外观类型,例如 返回类型取决于参数的模块值,或者至少取决于 路径(此处为
M

考虑这个例子:

module type Type = sig
  type t
end

let identity (module T : Type) (x : T.t) = x
这是错误的。错误消息指向
(x:T.T)
,并显示:

Error: This pattern matches values of type T.t
       but a pattern was expected which matches values of type T.t
       The type constructor T.t would escape its scope
您可以做的是在对第一类模块T进行抽象之前对所需类型进行抽象,这样就不再有转义了

let identity (type a) (module T : Type with type t = a) (x : a) = x
这依赖于对类型变量
a
进行显式抽象的能力。不幸的是,这个特性还没有扩展到更高级变量的抽象。您当前无法写入:

解决方案是使用一个函子:不在值级别工作,而是在模块级别工作,模块级别有更丰富的种类语言

module MonadOps (M : MonadSig) = struct
  open M
  let (>>=) = bind

  let sequence foo =
    List.fold_left (fun acc x ->  
      acc >>= fun acc' -> 
      x >>= fun x' -> 
      return (x' :: acc')
    ) (return []) foo;;
end

不是让每个单元操作(
序列
映射
,等等)在单元上进行抽象,而是在模块范围内进行抽象。

这个老问题可能对您有用:是的,我已经假设是依赖(-ish)类型导致了问题!谢谢你的详细回答。
let sequence (type 'a m) (module M : MonadSig with 'a t = 'a m) (foo : 'a m list) =
  ...
module MonadOps (M : MonadSig) = struct
  open M
  let (>>=) = bind

  let sequence foo =
    List.fold_left (fun acc x ->  
      acc >>= fun acc' -> 
      x >>= fun x' -> 
      return (x' :: acc')
    ) (return []) foo;;
end