2015-11-02 62 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 });;