Recursion 跨编译单元的OCaml递归模块

Recursion 跨编译单元的OCaml递归模块,recursion,module,ocaml,functor,Recursion,Module,Ocaml,Functor,我试图将以下递归模块拆分为单独的编译单元。具体地说,我希望B在它自己的B.ml中,能够与其他A一起重用它 module type AT = sig type b type t = Foo of b | Bar val f : t -> b list end module type BT = sig type a type t = { aaa: a list; bo: t option } val g : t -> t list end module rec

我试图将以下递归模块拆分为单独的编译单元。具体地说,我希望B在它自己的B.ml中,能够与其他A一起重用它

module type AT = sig
  type b
  type t = Foo of b | Bar
  val f : t -> b list
end

module type BT = sig
  type a
  type t = { aaa: a list; bo: t option }
  val g : t -> t list
end

module rec A : (AT with type b = B.t) = struct
  type b = B.t
  type t = Foo of b | Bar
  let f = function Foo b -> [ b ] | Bar -> []
end
and B : (BT with type a = A.t) = struct
  type a = A.t
  type t = { aaa: a list; bo: t option }
  let g b =
    let ss = List.flatten (List.map A.f b.aaa) in
    match b.bo with
    | Some b' -> b' :: ss
    | None -> ss
end

let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;
我不知道如何把它分成不同的单元

Xavier Leroy在这个主题上的下面一句话给了我希望,使用OCaml的模块语法进行编码是可能的:“该方案不支持编译单元之间的递归。但是,后者可以使用单独编译的函子进行编码,其固定点将在以后使用模块rec构造时获取”

我已经玩过模块rec,但似乎找不到一种方法来进行类型检查。在B的函数g中使用A的函数f似乎会引起问题


(就上下文而言,在原始代码中,A.t是指令类型,B.t是基本块类型。分支指令引用块,块包含指令列表。我想用不同的指令集重用基本块类型和相关函数。)

我认为这篇文章指的是这样的内容:

(* a.ml *)

module F (X : sig val x : 'a -> 'a end) =
struct
  let y s = X.x s
end


运行此(
ocamlc a.mlb.mlc.ml&&./a.out
)打印


显然,我使用的
A
B
的定义是毫无意义的,但是你应该能够将你自己的定义替换成这种模式,并且使用命名签名,而不是像我那样逐字逐句地写出来。

以下内容似乎有效,尽管它相当难看

(* asig.mli *)

module type AT = sig
  type b
  type b' (* b = b' will be enforced externally *)
  type t
  val f : t -> b' list
end

(* bsig.mli *)

module type BT = sig
  type a
  type b' (* t = b' will be enforced externally *)
  type t = { aaa: a list; bo: b' option }
  val g : t -> b' list
end

(* b.ml *)

open Asig

module MakeB(A : AT) = struct
  type a = A.t
  type t = { aaa: a list; bo: A.b' option }
  type b' = A.b'
  let g b =
    let ss = List.flatten (List.map A.f b.aaa) in
    match b.bo with
    | Some b' -> b' :: ss
    | None -> ss
end

(* a.ml *)

open Asig
open Bsig

module type ASigFull = sig
  type b
  type b'
  type t = Foo of b | Bar
  val f : t -> b' list
end

module type BMAKER = functor (A : AT) -> (BT with type a = A.t
                                              and type b' = A.b')
module MakeAB(MakeB : BMAKER) = struct

module rec B1 : (BT with type a = A1.t
                     and type b' = A1.b') = MakeB(A1)
       and A1 : (ASigFull with type b = B1.t
                           and type b' = B1.t) = struct
  type b = B1.t
  type b' = b
  type t = Foo of b | Bar
  let f = function Foo b -> [ b ] | Bar -> []

end

module A = (A1 : ASigFull with type t = A1.t and type b = B1.t and type b' := B1.t)
module B = (B1 : BT with type t = B1.t and type a = A1.t and type b' := B1.t)

end

module AB = MakeAB(B.MakeB)
module A = AB.A
module B = AB.B

let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;

如果我下面的回答无法解决您在拆分此文件时遇到的问题,请在
B.g
中发布您迄今为止在单独编译时的最佳尝试,以及您在
A.f
中遇到的类型错误。另外,请关注问题的结尾,还有一些其他方法来解决此问题–例如,在您的说明中,将基本块索引或键存储到数据结构中,而不是键入的基本块引用。谢谢antron,在尝试做出最佳尝试的同时,我显然偶然发现了一个解决方案,至少在这个测试用例中是这样。希望它能翻译成我的实际代码。祝你好运:)
(* c.ml *)

module rec A' : sig val y : 'a -> 'a end = A.F (B')
       and B' : sig val x : 'a -> 'a end = B.F (A')

let () =
  A'.y "hello" |> print_endline;
  B'.x "world" |> print_endline
hello
world
(* asig.mli *)

module type AT = sig
  type b
  type b' (* b = b' will be enforced externally *)
  type t
  val f : t -> b' list
end

(* bsig.mli *)

module type BT = sig
  type a
  type b' (* t = b' will be enforced externally *)
  type t = { aaa: a list; bo: b' option }
  val g : t -> b' list
end

(* b.ml *)

open Asig

module MakeB(A : AT) = struct
  type a = A.t
  type t = { aaa: a list; bo: A.b' option }
  type b' = A.b'
  let g b =
    let ss = List.flatten (List.map A.f b.aaa) in
    match b.bo with
    | Some b' -> b' :: ss
    | None -> ss
end

(* a.ml *)

open Asig
open Bsig

module type ASigFull = sig
  type b
  type b'
  type t = Foo of b | Bar
  val f : t -> b' list
end

module type BMAKER = functor (A : AT) -> (BT with type a = A.t
                                              and type b' = A.b')
module MakeAB(MakeB : BMAKER) = struct

module rec B1 : (BT with type a = A1.t
                     and type b' = A1.b') = MakeB(A1)
       and A1 : (ASigFull with type b = B1.t
                           and type b' = B1.t) = struct
  type b = B1.t
  type b' = b
  type t = Foo of b | Bar
  let f = function Foo b -> [ b ] | Bar -> []

end

module A = (A1 : ASigFull with type t = A1.t and type b = B1.t and type b' := B1.t)
module B = (B1 : BT with type t = B1.t and type a = A1.t and type b' := B1.t)

end

module AB = MakeAB(B.MakeB)
module A = AB.A
module B = AB.B

let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;