[英]Extending an existing type in OCaml
我最近一直在做一些OCaml編程來學習語言並且更熟悉函數式編程。 最近,我開始認為我希望能夠擴展現有類型(內置或我自己的類型),例如:
type bexp =
And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;
現在讓我們說我想在這種類型中添加一個Nop變體,但僅用於新類型 - 有點像繼承。 嘿,這些應該是代數數據類型,對吧? 那么為什么不是這樣的:
type nbexp = bexp | Nop nbexp ;;
...但這不是有效的OCaml,它給出了語法錯誤。 基本上,我想要做的就是說我希望nbexp包含bexp包含的所有內容,並為此添加一個Nop。 我想這是不可能的,因為,例如,如果您使用And構造函數,則無法確定它是bexp類型還是nbexp類型。 (我認為構造函數Nop采用nbexp也可能存在問題。)
那么有沒有辦法在OCaml中做這樣的事情? 而且,這是否是Haskell中可行的事情(也許是類型類)?
一個有趣的解決方案是使用多態變體:
type bexp =
[ `And of bexp * bexp
| `Or of bexp * bexp
| `Xor of bexp * bexp
| `Not of bexp ];;
type nbexp = [ bexp | `Nop of nbexp ];;
請注意,多態變體比普通變體更棘手,但允許擴展類型。
一個有趣的表達式評估示例,帶有擴展,使用多態變體可以在ocaml源的測試目錄中找到,請參閱svn
嘿,這些應該是代數數據類型,對吧?
對。 代數數據類型由標記(也稱為區分)的聯合和產品構成。 你想要的只是一個(非標記的)聯合,它不是代數數據類型,Haskell不支持。 OCaml具有多態變體(參見其他答案)。
Typed Scheme確實支持未標記的聯合,因此您可能需要檢查它。
正如你自己正確猜測的那樣,這在代數類型中是不可能的。 我同意Apocalisp的建議,你可以簡單地將nbexp
的“繼承”部分nbexp
在它自己的構造函數中。
我想補充一點,代數類型的遺傳缺乏是他們精彩的一部分。 這意味着諸如And(foo, bar)
類的表達式被粗略地鍵入,並且轉換(向上或向下)在類型系統中沒有任何作用。 這樣可以提高安全性和清晰度。 它當然需要程序員明確處理他/她想要與bexp
部分交互的nbexp
,但是如果你考慮它,那就是如何在實踐中實現更高的安全性和清晰度。
更新:Ocaml現在具有可擴展類型。 http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec246
你會這樣做
type bexpr += Nop of bexpr
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.