具有参数类型的第一类模块(类型构造函数Ff将逃避其范围)

LiK*_*Kao 5 ocaml types module locally-abstract-type

我目前正在玩模块,看看它们可以以类似的方式用于Haskell类型类.目前我正在尝试使用仿函数类型:

module type Functor =
   sig
      type 'a f
      val fmap : ('a -> 'b) -> ('a f -> 'b f)
   end


module IdFunc =
   struct
      type 'a f  = Id of 'a
      let fmap f = fun (Id a) -> Id (f a)
      let runId  (Id a) = a
   end

let outmap (module F : Functor) av = F.fmap f av
Run Code Online (Sandbox Code Playgroud)

但是在这种情况下outmap输入不正确,编译器会产生错误The type constructor F.f would escape its scope.我知道为什么在这种情况下会导致这个错误,但我不知道如何解决它(因为类型f是参数化的).

我已经尝试使用本地抽象类型:

let outmap (type s) (module F : Functor with type 'a f = s) f av = F.fmap f av
Run Code Online (Sandbox Code Playgroud)

要么

let outmap (type a) (type b) (type fa) (type fb) 
 (module F : Functor with type a f = fa type b f = fb) f av = 
 F.fmap f av
Run Code Online (Sandbox Code Playgroud)

要么

let outmap (type s) (module F : Functor with type f = s) f av = F.fmap f av
Run Code Online (Sandbox Code Playgroud)

这些只是给我各种语法错误或输入错误.

有什么方法可以解决这个问题吗?

在Haskell中,这只是:

outmap : Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

什么是ocaml中的等价物(如果有的话)?

====编辑====

我找到了一种获得类似工作的方法:

module type Functor =
   sig
      type a
      type b
      type af
      type bf
      val fmap : (a -> b) -> (af -> bf)
   end

module type FromTo =
   sig
      type a
      type b
   end

module IdFunc =
   functor (FT : FromTo) -> 
   struct
      type a = FT.a
      type b = FT.b
      type 'a f  = Id of 'a
      type af = a f
      type bf = b f
      let fmap f = fun (Id a) -> Id (f a)
      let runId  (Id a) = a
   end

let outmap (type a') (type b') (type af') (type bf') 
   (module F : Functor 
      with type a  = a'  and
           type b  = b'  and
           type af = af' and
           type bf = bf') 
   f av =  F.fmap f av

module M = IdFunc(struct type a = int type b = string end)

let oi = outmap (module M)

let test = oi (fun _ -> "Test") (M.Id 10)
Run Code Online (Sandbox Code Playgroud)

但这似乎增加了许多复杂性,这可能会更简单.

Leo*_*ite 8

我担心你无法直接表达你想要做的事情,因为它是一个高级多态性(类型构造函数的多态性)的例子,这在OCaml的核心语言中是不受支持的.

有关为什么OCaml的核心语言不能支持更高通道的多态性的解释,请参阅轻量级高度多态性的 1.1节.

由于模块系统确实支持更高级别的多态性,因此解决此问题的通常方法是创建outmap函子而不是函数.

或者,上面链接的论文描述了一种解决方法(在higher库中实现- 在opam上可用),它基本上在类型级别使用defunctionalisation.这是否比使用仿函数更方便取决于您的具体用例.