2011-01-20 77 views
9

在OCaml中使用相互遞歸模塊定義時,即使在.ml文件中也需要簽名。這是一個煩惱,我也想暴露.mli給定的接口,因爲我最終重複簽名兩次。 :(!爲什麼要在OCaml中的相互遞歸模塊中籤名?

module rec Client : sig 
    type ('serv,'cli) t 

    (* functions ... *) 
end = struct 
    type ('serv,'cli) t = 
    { server: ('serv,'cli) Server.t 
    ; (* other members ... *) 
    } 
end 
and Server : sig 
    type ('serv,'cli) t 

    (* functions ... *) 
end = struct 
    type ('serv,'cli) t = 
    { mutable clients: ('serv,'cli) Client.t list 
    ; mutable state: 'serv 
    } 

    (* functions again ... *) 
end 

這是我在做什麼粗略的估計(Client類型的對象知道實例化他們ServerServer■正確的Client S)。

當然,簽名。反覆在.mli爲什麼這是必要的

(注:我不是在抱怨,但實際上想知道是否有一種理論或「硬編譯器問題」有關的原因)?

回答

4

我的猜測:爲了編譯遞歸模塊編譯器需要實現類型註釋。在mli文件中(如果使用的話)可以進一步限制或隱藏這些模塊的類型,因此一般情況下編譯器不希望在解析類型遞歸時找到有用的類型。

+0

這很有道理。事實上,我通過在`.mli`中暴露外部消費者的不同類型簽名來利用這個「特徵」。我應該已經意識到了。 – Ashe 2011-01-21 11:02:39

7

據我所知,這是沒有辦法的。就編譯器而言,在很高的層次上,客戶端的類型簽名是不完整的,直到它知道服務器的類型簽名,反之亦然。原則上,有一種解決方法:編譯器可以在編譯時交叉引用.mli文件。但是這種方法有缺點:它將編譯器和鏈接器的一些職責混合在一起,並且使得模塊化編譯(不是雙關語)更加困難。

如果您有興趣,我推薦Xavier Leroy的original proposal遞歸模塊。

+0

感謝您的鏈接!類型理論略高於我,但仍然是一個很好的閱讀。但是我想像ygrek提到的那樣,不是爲了.mli聲明用於編譯實際模塊本身的類型。正如你所提到的,如果它試圖這樣做,它會變得更加難看。 – Ashe 2011-01-21 11:08:52