5

我目前正在使用模块,看看它们可以以与 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将无法正确键入,编译器会产生错误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

或者

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

或者

let outmap (type s) (module F : Functor with type 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)

但这看起来增加了很多复杂性,因为这可能应该更简单。

4

2 回答 2

8

恐怕你不能直接表达你想要做什么,因为它是 OCaml 的核心语言不支持的高级多态性(类型构造函数上的多态性)的一个例子。

关于为什么 OCaml 的核心语言不能支持更高种类的多态性的解释,请参见轻量级更高种类的多态性中的 1.1 节。

由于模块系统确实支持更高种类的多态性,因此该问题的通常解决方案是制作outmap函子而不是函数。

或者,上面链接的论文描述了一种解决方法(在higher库中实现——在 opam 上可用),它基本上在类型级别使用去功能化。这是否比使用仿函数更方便取决于您的特定用例。

于 2014-06-24T13:00:44.873 回答
2

使用上述论文中的想法(假设您已经定义appNewtype1按照论文中的描述或使用higheropam 中的包),您可以将仿函数定义为:

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

更多示例,您可以查看https://github.com/hongchangwu/ocaml-type-classes

于 2016-11-23T05:24:42.187 回答