如何在OCaml中将模块映射到模块类型?

时间:2019-02-20 09:18:33

标签: ocaml

我想定义一个依赖于其他模块的模块类型。我以为可以用函子来做,但是我相信函子只是从模块到模块的映射,不可能使用它们来定义从模块到模块类型的映射。

这是我想做的事的一个例子:

module type Field =
sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module type Func (F1 : Field) (F2 : Field) =
sig
  val eval : F1.t -> F2.t
end

module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2) =
struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end

我有一个Field模块类型,例如实数和有理数,我想从一个字段到另一个字段定义函数Func的类型,即F1.t -> F2.t对于任何两个给定的模块F1F2。有了这些模块类型之后,我可以定义FuncField,它使用F1F2F并基本上用F.eval来扩充addmul

运行代码时,在定义Error: Syntax error的行中得到通用的Func。有没有办法在OCaml中定义类似的东西?

我不确定这是否需要依赖类型,但是我对Coq有点依赖,因为Coq具有依赖类型,并且在定义等效构造时也不会抱怨:

Module Type Field.
  Parameter T : Type.
  Parameter add : T -> T -> T.
  Parameter mul : T -> T -> T.
End Field.

Module Type Func (F1 : Field) (F2 : Field).
  Parameter eval : F1.T -> F2.T.
End Func.

Module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2).
  Definition eval a := F.eval a.
  Definition add a b := F2.add (F.eval a) (F.eval b).
  Definition mul a b := F2.mul (F.eval a) (F.eval b).
End FuncField.

2 个答案:

答案 0 :(得分:3)

功能键是各个模块之间的功能。从模块类型到模块类型都没有函子,但您可以作弊。 :)

与Coq不同,OCaml的模块不是完全依赖的类型,但在这种情况下它们“足够依赖”。 这个想法是模块可以包含模块类型。由于我们不能直接返回模块类型,因此我们只返回包含一个模块的模块!

您的示例变成这样:

module type Field = sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module Func (F1 : Field) (F2 : Field) = struct
  module type T = sig
    val eval : F1.t -> F2.t
  end
end

module FuncField (F1 : Field) (F2 : Field) (F : Func(F1)(F2).T) = struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end

请注意Func(F1)(F2).T语法,该语法表示“应用函子,并从结果中获取模块类型T”。 functor应用程序+字段访问的这种组合仅在类型(普通类型或模块类型)中可用。

我不记得我是在哪里找到这个技巧的,但是您可以在tyxml(definitionusage)的“生产中”操作中看到它。

答案 1 :(得分:1)

稍微走开框框,因为似乎您真的不需要仿函数来完成所描述的内容。简单的模块约束就足够了:

module type Field =
sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module type Func =
sig
  type t1
  type t2
  val eval : t1 -> t2
end

module FuncField (F1 : Field) (F2 : Field) (F : Func with type t1 = F1.t and type t2 = F2.t) =
struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end