2011-07-30 44 views
11

在Ocaml中,是否有一個簡單的構造/樣式來擴展定義的類型?在Ocaml中重複使用和擴展已定義的類型

說,如果我們有boolean類型

bool2 = True | False 

現在我們希望把它擴大爲3值邏輯。 OCaml中,有更優雅的人比重新定義BOOL2這樣的:

bool3 = True | False | ThirdOne 

回答

8

我會建議不要濫用多態變體。它們在紙上看起來不錯,但更靈活的推斷和分類將隨時讓你回頭。當我使用多態變體時,我嘗試確保每個用法都使用精確的約束類型表達式進行註釋。

我建議回去修改舊的代碼,因爲這似乎很自然。如果你在編寫代碼時考慮了可擴展性,特別是在bool2類型上避免了_-模式,那麼編譯器會警告你任何地方都假設只有兩個構造函數。編譯器對類型修改的反饋非常有用,因爲它是使程序正確的機械幫助。

這種做事方式當然有一些缺點。其中之一就是修改類型定義,然後修改每個用例可能不適用於您通常的編譯測試實踐:如果您在大型代碼庫上執行此操作,那麼在項目編譯之前您需要做很多事情乾淨地再次(因此可以被測試)。您可能會將修改分成多個版本控制系統,但這意味着一些中間承諾狀態不會編譯,這並不令人滿意。另一種可能性是僅僅爲了增加運行時失敗而改變這些地方(| Third_one -> assert false),那麼你就有可編譯的代碼,你可以在應用程序測試期間的運行時糾正這些失敗。但我仍然認爲靜態編譯器反饋對於代碼維護很有幫助。

還有一種選擇是將代數數據類型封裝在「擴展代數數據類型」type bool3 = New | Old of bool2中,在您給出的作爲Martin答覆評論的鏈接中討論了該代碼數據類型。這可能是在不破壞編譯的情況下從一種數據類型轉換到另一種數據類型的好方法,但從長遠來看,這是很痛苦的,尤其是如果您將更多的擴展堆疊在一起。

當然,在某些情況下真正需要的是通過代碼添加來擴展數據類型的方法,而不是通過代碼修改來實現靜態安全,更易於編譯,運行和測試,以及在運行時高效。這是Expression Problem的一個實例,其中它們是各種解決方案,多態變體就是其中之一。但在一般情況下,您不需要額外的靈活性來添加代碼,並且不值得增加有關語言功能的複雜性,所以我建議堅持使用普通的舊變體類型,除非它明顯是一個巨大的有所不同。 PS:關於多態性變體及其與表達問題的關係,強制性論文是Jacques Garrigue的Code reuse through polymorphic variants

14

多態變體提供了這種功能:

type bool2 = [ `True | `False ] 
type bool3 = [ bool2 | `Third_one ] 

就是這樣。

多態變體還有另一種有用的捷徑。在模式匹配中,使用由之前#類型名稱:

let is_bool2 = function 
    #bool2 -> true 
    | `Third_one -> false 

多態變體,應謹慎使用,因爲它們可以很容易導致混亂的錯誤消息。如果原始類型bool2無論如何都不是多態變體,那麼兩種類型的聯合可以如下實現。假設bool2是核心類型bool,採用經典的款式的定義是:

 
type bool3 = Bool of bool | Third_one 

在模式匹配,編譯器會檢查所有的情況都包括在內,無需類型標註。它看起來像這樣:

 
match x with 
| Bool true -> ... 
| Bool false -> ... 
| Third_one -> ... 
+1

想象一下bool2是庫中定義的一種類型。顯然,通過多態變體提出的方法需要我們重新定義bool2從monopolymorphic到多態的最初定義。所以我想短時間直接回復我的問題是:不,我們需要重新定義bool2以將其擴展到bool3。對,馬丁?謝謝。 – zell

+0

哦,我在http://stackoverflow.com/questions/1746743/extending-existing-type-in​​-ocaml發現了一個非常類似的問題。 – zell

1

根據您的任務,您可能還會發現Extensible Variant Types有用。更多信息和用例here

type bool = .. 
type bool += 
    | True 
    | False 

(* Elsewhere *) 
type bool += 
    | Third_one