2016-09-20 67 views
1

是否支持定義只能通過特定功能實例化的類型的語言或類型系統。綁定到特定功能的名義類型

一個示例可能是與函數CreateNonZeroInteger綁定的類型NonZeroInteger。任何外部代碼都可以訪問該類型,接收和返回此類型的值。但重要的是,只能通過調用函數CreateNonZeroInteger

NonZeroInteger應該名義上鍵入來創建該類型的值。具有相同結構的另一種類型的值不應與此類型相比或可鑄造。

+5

我認爲這通常是用隱藏數據構造函數的模塊來完成的,並暴露了一個包裝數據構造函數的函數。在這裏看到最佳答案:http://stackoverflow.com/questions/39531032/using-types-to-force-correctness – zoran119

+0

在f#中,您可以使用訪問修飾符,但它會很醜陋 –

+1

「*是否有語言或類型系統它支持定義只能通過特定函數實例化的類型。*「好吧,C++ for one;但我不知道任何基於_Hindley-Milner的類型系統完全支持它,這似乎是你實際要求的。 – ildjarn

回答

7

創建一個類型,定義一個函數來創建該類型的值,然後導出類型和函數,但不是而是該類型的數據構造函數。例如,在Haskell,給你的例子:

module My.Module.NonZeroInteger (NonZeroInteger, createNonZeroInteger) where 

newtype NonZeroInteger = NonZeroInteger Integer 
    deriving (Show, Eq, Ord) 

createNonZeroInteger :: Integer -> Maybe NonZeroInteger 
createNonZeroInteger 0 = Nothing 
createNonZeroInteger x = Just $ NonZeroInteger x 

My.Module.NonZeroInteger消費者將能夠創建NonZeroInteger類型的值,但由於數據的構造不出口,他們將永遠不會成爲能夠創造NonZeroInteger小號這是內部0

自定義構造函數,在這種情況下爲createNonZeroInteger,傳統上稱爲「smart constructor」

+0

我真的希望類型本身綁定到簽名中的函數,而不是利用模塊封裝。但這真的很有幫助,並回答了這個問題。 –

2

我覺得值得在這裏記錄下來,你可以做到亞歷克西斯金在F#中建議的完全一樣的東西,通過使工會案例構造函數private

type NonZeroInteger = private NonZeroInteger of int 

let tryCreateNonZeroInteger = function 
    |0 -> None 
    |x -> Some <| NonZeroInteger x 

該類型本身仍然是可公開訪問的,但它只能通過您提供的函數創建和分解。