跨编译单元的OCaml递归模块 [英] OCaml recursive modules across compilation units
问题描述
我正在尝试将以下递归模块拆分为单独的编译单元.具体来说,我希望B位于自己的b.ml中,以便能够与其他A一起重用.
I'm trying to split the following recursive modules into separate compilation units. Specifically, I'd like B to be in its own b.ml, to be able to reuse it with other A's.
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 });;
我不知道如何将其拆分为多个单元.
I can't figure out how to split it across units.
以下主题的Xavier Leroy的 paper 给我希望可以使用OCaml的模块语法进行编码:该建议不支持编译单元之间的递归.但是,可以使用单独编译的函子对后者进行编码,稍后将使用模块rec构造获取其固定点".
The following sentence from Xavier Leroy's paper on the topic gives me hope that it's possible to encode using OCaml's module syntax: "the proposal does not support recursion between compilation units. The latter can however be encoded using separately-compiled functors, whose fix-point is taken later using the module rec construct".
我玩过rec模块,但似乎找不到找到类型的方法.在B的函数g中使用A的函数f似乎会造成麻烦.
I've played around with module rec but can't seem to find a way to make it type-check. The use of A's function f inside B's function g seems to cause the trouble.
(对于上下文,在原始代码中,At是指令类型,而Bt是基本块类型.分支指令引用了块,并且这些块包含指令列表.我想重用基本块类型和相关联的代码具有不同指令集的功能.)
(For the context, in the original code A.t is an instruction type, and B.t is a basic block type. Branch instructions reference blocks, and blocks contain lists of instructions. I'd like to reuse the basic block type and associated functions with different instruction sets.)
推荐答案
我认为本文所指的是这样的东西:
I think the paper is referring to something like this:
(* 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
的定义是胡说八道,但是您应该能够将自己的定义替换为该模式,以及使用命名签名而不是像我一样将它们写出来.
Obviously, the definitions of A
and B
I used are nonsense, but you should be able to substitute your own definitions into this pattern, as well as use named signatures instead of writing them out literally like I did.
这篇关于跨编译单元的OCaml递归模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!