我正在尝试将以下递归模块拆分为单独的编译单元。具体来说,我希望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关于该主题的paper的以下句子让我希望可以使用OCaml的模块语法进行编码:“该提议不支持编译单元之间的递归。然而,后者可以使用单独编码 - 编译的仿函数,其修复点稍后使用模块rec构造“。
我玩过模块rec但似乎无法找到一种方法来进行类型检查。在B函数g中使用A函数f似乎会造成麻烦。
(对于上下文,在原始代码中,At是指令类型,Bt是基本块类型。分支指令引用块,块包含指令列表。我想重用基本块类型和关联具有不同指令集的函数。)
答案 0 :(得分:2)
我认为这篇论文指的是这样的:
(* a.ml *)
module F (X : sig val x : 'a -> 'a end) =
struct
let y s = X.x s
end
(* b.ml *)
module F (Y : sig val y : 'a -> 'a end) =
struct
(* Can use Y.y s instead to get infinite loop. *)
let x s = Y.y |> ignore; s
end
(* 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
运行此(ocamlc a.ml b.ml c.ml && ./a.out
)打印
hello
world
显然,我使用的A
和B
的定义是无意义的,但您应该能够将自己的定义替换为此模式,以及使用命名签名而不是字面写出来像我一样。
答案 1 :(得分:1)
以下似乎有效,尽管它很难看。
(* 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 });;