Это типобезопасный и проверяется во время компиляции.
Как вы уже указали в комментариях к своему вопросу, он не проверяется во время компиляции. Также нет эквивалентной функциональности в модуле-2 или любом другом готовом к выпуску универсальном языке программирования.
Возможность проверки ограничений, подобных этому во время компиляции, - это то, что требует зависимых типов, типов уточнения или подобных конструкций. Вы можете найти такие функции в теоретических теоремах, как Coq или Agda или в экспериментальных/академических языках, например ATS или Liquid Haskell.
Теперь из тех языков, которые я упомянул, Coq и Agda определяют рекурсивно их типы Nat
, так что это не то, что вы хотите, и ATS является обязательным языком. Так что листья Liquid Haskell (плюс языки, о которых я не упоминал, конечно). Liquid Haskell - это Haskell с аннотациями дополнительного типа, поэтому он определенно является функциональным языком. В Liquid Haskell можно определить MyNat
(тип с именем Nat
уже определен в стандартной библиотеке) типа как это:
{[email protected] type MyNat = {n:Integer | n >= 0} @-}
, а затем использовать его как это:
{[email protected] fac :: MyNat -> MyNat @-}
fac :: Integer -> Integer
fac 0 = 1
fac n = n * fac (n-1)
Если вы попробуете для вызова fac
с отрицательным числом в качестве аргумента вы получите ошибку компиляции. Вы также получите ошибку компиляции, если вы вызываете ее с пользовательским вводом в качестве аргумента, если вы специально не убедитесь, что вход был неотрицательным. Вы также получите ошибку компиляции, если вы удалили строку fac 0 = 1
, потому что теперь n
на следующей строке может быть 0, что делает n-1
отрицательным при вызове fac (n-1)
, поэтому компилятор отвергнет это.
Следует отметить, что даже при использовании современных методов вывода типов нетривиальные программы на таких языках будут иметь довольно сложные сигнатуры типов, и вы потратите много времени и усилий на гонку ошибки через все более сложные джунгли типов подписей, имеющих только непонятные ошибки типа, которые помогут вам. Таким образом, есть цена на безопасность, которая предлагает вам такие функции, как эти. Следует также отметить, что на полном языке Тьюринга вам иногда придется записывать проверки времени выполнения для случаев, которые, как вы знаете, не могут произойти, поскольку компилятор не может доказать все, даже если вы думаете, что это должно произойти.
Вы имеете в виду '(deftype natural() '(integer 0))' в Common Lisp, например? – Dirk
@ Dirk Я не знаю Lisp. Поэтому я не понимаю, что это значит. Я знаю Haskell с функциональных языков. Я хочу, чтобы определить Natural как подтип Integer, а не как оболочку Integer, если это то, что вы набрали. – Dragno
Это определение типа («тип' natural' состоит из всех 'integer' равно или больше 0 "), что несколько эквивалентно вашему примеру Ada (за исключением верхней границы диапазона). Вы спросили «любой функциональный» язык, поэтому я дал вам Lisp ... – Dirk