Types 具有参数类型的第一类模块(类型构造函数F.F将脱离其范围)

Types 具有参数类型的第一类模块(类型构造函数F.F将脱离其范围),types,module,ocaml,locally-abstract-type,Types,Module,Ocaml,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)

我目前正在研究模块,看看它们可以以何种方式以类似于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
但是,在这种情况下,
outmap
将无法正确键入,编译器将生成错误
,类型构造函数F.F将退出其作用域
。我知道在这种情况下为什么会出现这个错误,但我不确定如何解决它(因为类型f是参数化的)

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

let outmap (type s) (module F : Functor with type 'a f = s) f av = F.fmap f av

这些都给了我各种语法错误或打字错误

有办法解决这个问题吗

在Haskell中,这只是:

outmap : Functor f => (a -> b) -> f a -> f b
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)

但这似乎增加了很多复杂性,因为有些事情可能会简单得多。

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

有关OCaml核心语言无法支持更高级多态性的解释,请参阅中的第1.1节

由于模块系统确实支持更高级的polymophism,因此通常解决此问题的方法是将
outmap
设置为函子而不是函数


或者,上面链接的文章描述了一种变通方法(在
更高版本的
库中实现——可在opam上获得),它基本上在类型级别上使用失效。这是否比使用functor更方便取决于您的具体用例。

使用上述论文中的思想(假设您已定义了论文中所述的
app
Newtype1
,或者使用opam中的
更高版本的
包),您可以将functor定义为:

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

module Id = Newtype1(struct type 'a t = 'a end)

module IdFunc : Functor with type t = Id.t = struct
  type t = Id.t
  let fmap f x = x |> Id.prj |> f |> Id.inj
end

let runId (x : ('a, Id.t) app) : 'a = Id.prj x

let outmap (type a)
           (module F : Functor with type t = a)
           f av =
  F.fmap f av
有关更多示例,您可以查看

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)
module type Functor = sig
  type t
  val fmap : ('a -> 'b) -> ('a, t) app -> ('b, t) app
end

module Id = Newtype1(struct type 'a t = 'a end)

module IdFunc : Functor with type t = Id.t = struct
  type t = Id.t
  let fmap f x = x |> Id.prj |> f |> Id.inj
end

let runId (x : ('a, Id.t) app) : 'a = Id.prj x

let outmap (type a)
           (module F : Functor with type t = a)
           f av =
  F.fmap f av