我正在尝试将以下递归模块拆分为单独的编译单元。具体来说,我希望 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 是基本块类型。分支指令引用块,块包含指令列表。我想重用不同的基本块类型和关联函数指令集。)
最佳答案
我认为这篇论文是指这样的事情:
(* 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
我用的是废话,但你应该能够将你自己的定义替换到这个模式中,以及使用命名签名而不是像我那样从字面上写出来。
关于recursion - 跨编译单元的 OCaml 递归模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33479679/