类型由仿函数构建的两个模块之间的关系

时间:2012-01-31 20:19:23

标签: types module ocaml functor

我已经定义了几个签名和模块如下:

module type MATRIX =
sig
  type 'a t
  val init: 'a -> 'a t
end

module type MMM =
sig
  type 'a t
end

module type AMATRIX =
sig
  include MATRIX
  module Mmm : MMM
  module Matrix: MATRIX
  val mmm_of_amatrix: 'a t -> int -> int -> 'a Mmm.t
end

module type AREAMMM =
sig
  type t
  module Mmm: MMM
  val make: int Mmm.t -> t
end

module MatrixArray: MATRIX =
struct
  type 'a t = 'a array array
  let init (e: 'a) : 'a t = failwith "to do"
end

module MmmArray: MMM =
struct
  type 'a t = 'a array array
end

还有两个仿函数:

module AMatrixFun: functor (Mmm: MMM) -> functor (Matrix: MATRIX) -> AMATRIX
  with
    module Mmm = Mmm
  and
    module Matrix = Matrix =
      functor (Mmm: MMM) -> functor (Matrix: MATRIX) ->
    struct
      include MatrixArray
      module Mmm = Mmm
      module Matrix = Matrix
      let mmm_of_amatrix (m: 'a t) (nr_i: int) (nc_i: int) : 'a Mmm.t = failwith "to do"
    end

module AreaMmmFun : functor (Mmm: MMM) -> AREAMMM
  with module Mmm = Mmm =
    functor (Mmm: MMM) ->
  struct
    type t
    module Mmm = Mmm
    let make (x: int Mmm.t) : t = failwith "to do"
  end

使用一些模块应用函子:

module AMatrix  = AMatrixFun(MmmArray)(MatrixArray)
module AreaMmm  = AreaMmmFun(MmmArray)

let a = AMatrix.mmm_of_amatrix (AMatrix.init 5) 0 0
let b = AreaMmm.make a

这段代码的编译工作正常。但是,如果我将最后一部分更改为

module AMatrix : AMATRIX = AMatrixFun(MmmArray)(MatrixArray)
module AreaMmm : AREAMMM = AreaMmmFun(MmmArray)

let a = AMatrix.mmm_of_amatrix (AMatrix.init 5) 0 0
let b = AreaMmm.make a

编译在最后一行停止,然后给我:

File "lib/tools.ml", line 69, characters 21-22:
Error: This expression has type int AMatrix.Mmm.t
       but an expression was expected of type int AreaMmm.Mmm.t

我真的想将: AMATRIX添加到AMatrix: AREAMMM添加到AreaMmm,因为这可以确保这两个模块受这两个签名的约束。有人可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

我仍然不知道你想要实现什么,但如果你的目标是在你的模块之间实现某种继承(正如你在之前的一些主题标题中所说的那样),你可能需要使用递归模块。

例如,您首先要定义模块层次结构:此处S是初始模块签名,可以S1S2扩展:

module type S = sig
  type 'a t
end

module type S1 = sig
  include S
  val f: 'a -> 'a t
end

module type S2 = sig
  include S
  val g: 'a t -> 'a
end

然后,您创建具体的实现,它确切地定义了什么是'a t,并实现了S1S2所需的所有功能:

module Concrete = struct
  type 'a t = 'a array
  let f a = [| a |] (* fill with the right contents *)
  let g a = a.(0)   (* fill with the right contents *)
end

然后,通过使用正确的签名约束实现来抽象类型'a t。您需要这里的递归模块(请注意rec关键字):

module rec I : S = Concrete
and I2 : S2 with type 'a t = 'a I.t = Concrete
and I1 : S1 with type 'a t = 'a I.t = Concrete

你可以测试你的结果:

let a = I2.g (I1.f 0)

按预期返回0

答案 1 :(得分:1)

您的应用程序需要知道AMatrix.Mmm.tAreaMmm.Mmm.t相同,否则您将无法使用由一个模块创建的值在其他模块。

正如我之前所解释的,如果您断言module AMatrix : AMATRIX,那么您将丢弃AMatrix中未包含的AMATRIX内容的任何其他信息。特别是,由于AMATRIX未提及AMatrix.Mmm.tAreaMmm.Mmm.t相同,因此该信息将丢失且代码无法编译。

你应该断言的是:

module AMatrix : AMATRIX 
  with module Mmm = MmmArray 
   and module Matrix = MatrixArray