2015-11-02 32 views
2

我试图将下列递归模块拆分为单独的编译单元。具体来说,我希望B能够使用它自己的b.ml,以便能够与其他A一起使用。跨编译单元的OCaml递归模块

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 });; 

我不知道如何跨单位拆分它。

从话题泽维尔乐华paper下面的句子给了我希望,它可能使用的OCaml的模块语法来编码:“建议不支持编译单元之间递归后者可以但是使用单独编译函子来编码,其后续使用模块rec结构来确定其固定点“。

我已经玩过模块rec,但似乎无法找到一种方法来进行类型检查。在B的函数g中使用A的函数f似乎会造成麻烦。

(关于上下文,在原始代码中,At是指令类型,Bt是基本块类型,分支指令引用块和块包含指令列表,我想重用基本块类型和。相关的功能具有不同的指令集)

+0

如果我的回答如下不能解决您与分裂这个文件有问题,请迄今发表您的最好的尝试在不同的编译,并且你在'博伽混得​​'Af'类型错误'。 – antron

+0

此外,关注问题的结尾,还有其他方法可以解决此问题 - 例如,在指令中将基本块索引或键存储到数据结构中,而不是键入基本块参考。 – antron

+1

谢谢antron,在尝试提出最佳尝试时,我显然偶然发现了一个解决方案,至少在这个测试案例中。希望它会翻译成我的实际代码。 –

回答

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

以下似乎工作,虽然它是相当丑陋。

(* 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 });;