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

如何将模块映射到OCaml中的模块类型?,ocaml,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 -&g

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

下面是我想做的一个例子:

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
我有一个
字段
模块类型,比如实数和有理数,我想定义从一个字段到另一个字段的函数类型
Func
,对于任意两个给定模块
F1
F2
。有了这些模块类型,我就可以定义
FuncField
,它采用
F1
F2
F
,基本上用
add
mul
来扩充
F.eval

当我运行代码时,我在定义
Func
的行中得到一个通用的
错误:语法错误。有没有办法在OCaml中定义类似的内容

我不确定这是否需要依赖类型,但我对具有依赖类型的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.

函子是从一个模块到另一个模块的函数。从模块类型到模块类型之间没有函子。。。。但是你可以作弊

与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(,)中看到它在“生产”中的作用。

有点超出了框架,因为看起来你并不真的需要一个函子来完成你所描述的。简单的模块约束可能就足够了:

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

那是个聪明的把戏。不过,我在实例化模块时遇到了麻烦。这没有编译(不幸的是,这可能会将其全部折叠为一行):模块FloatField:Field=struct type t=float让我们添加一个b=a+。b设mul a b=a*。b端模块MulByTwo=struct let eval a=2.0*。一个终端模块MulByTwoField=FuncField(FloatField)(FloatField)(MulByTwo),这仅仅是因为约束
FloatField:Field
隐藏了
FloatField.t=float
的事实。删除它,它就会编译。