2016-09-20 6 views
1

Существует ли язык или система типов, которая поддерживает определение типов, которые могут быть созданы только через определенную функцию.Номинальные типы, связанные с определенной функцией

Примером может быть тип NonZeroInteger, который связан с функцией CreateNonZeroInteger. Любой внешний код может получить доступ к типу, получить и вернуть значения этого типа. Но принципиально, значение этого типа может быть создано только путем вызова функции CreateNonZeroInteger

NonZeroInteger должно быть номинально типизировано. Значение другого типа с той же структурой не должно быть сопоставимым или непригодным для этого типа.

+5

Я думаю, что это обычно делается с помощью модуля, который скрывает конструктор данных и предоставляет функцию, которая обертывает конструктор данных. См. Главный ответ здесь: http://stackoverflow.com/questions/39531032/using-types-to-force-correctness – zoran119

+0

В f # вы можете использовать модификаторы доступа, но это было бы уродливо –

+1

"* Есть ли язык или тип системы который поддерживает определение типов, которые могут быть созданы только через определенную функцию. * «Ну, C++ для одного; но я не знаю ни одной системы типа «Hindley-Milner-based_ type», которая полностью поддерживает ее, что похоже на то, что вы на самом деле спрашиваете. – 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 #, создав конструкторы case union private.

type NonZeroInteger = private NonZeroInteger of int 

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

Сам тип остается общедоступным, но его можно создавать и разлагать только через функции, которые вы предоставляете.

Смежные вопросы