Типы, которые параметризованы значениями, называются зависимыми типами .¹ Было проведено много исследований по теме зависимых типов, но мало что достигло «основного языка».
Большая проблема с зависимыми типами состоит в том, что если ваши типы содержат выражения, то есть биты кода, то средство проверки типов должно иметь возможность выполнять код.Это не может быть сделано в полной общности: что, если код имеет побочные эффекты?Что делать, если код содержит бесконечный цикл?Например, рассмотрим следующую программу в C-подобном синтаксисе (проверка ошибок опущена):
int a, b;
scanf("%d %d", &a, &b);
int u[a], v[b];
Как компилятор может узнать, имеют ли массивы u
и v
одинаковый размер?Это зависит от номеров, которые вводит пользователь!Одним из решений является запрет побочных эффектов в выражениях, которые появляются в типах.Но это не заботится обо всем:
int f(int x) { while (1); }
int u[f(a)], v[f(b)];
компилятор войдет в бесконечный цикл, пытаясь определить, имеют ли u
и v
одинаковый размер.
Итак, давайте запретим побочные эффекты внутри типов и ограничим рекурсию и зацикливание делами, которые можно окончательно завершить.Делает ли это проверку типов разрешимой?С теоретической точки зрения да, может.То, что у вас есть, может быть чем-то вроде Coq доказательства Проблема в том, что проверка типов тогда легко разрешима , если у вас достаточно аннотаций типов (аннотации типов - это информация о типах, предоставляемая программистом).И здесь достаточно много значит много.Очень многоКак, например, аннотации типов в каждой отдельной языковой конструкции, не только объявления переменных, но также вызовы функций, операторы и все остальное.И типы будут представлять 99,9999% от размера программы.Часто было бы быстрее написать все это на C ++ и отладить его , чем писать всю программу со всеми необходимыми аннотациями типов.
Следовательно, здесь трудность заключается в том, чтобы иметь систему типов, которая требуеттолько разумное количество аннотаций типа.С теоретической точки зрения, как только вы разрешаете опускать некоторые аннотации типов, это становится проблемой вывода типа , а не просто проверкой типа.И вывод типа неразрешим для даже относительно простых систем типов.Вы не можете легко иметь разрешимую (гарантированно прерванную) статическую (работающую во время компиляции) разумную (не требующую безумного количества аннотаций типов) систему зависимых типов.
Зависимые типы иногда появляются в ограниченной форме в основных языках.Например, C99 допускает массивы, размер которых не является константным выражением;тип такого массива является зависимым типом.Неудивительно, что для C компилятору не требуется проверять границы для такого массива, даже когда требуется проверять границы для массива постоянного размера.
Полезно, Зависит от ML это диалект ML с типами, которые могут быть проиндексированы с помощью простых целочисленных выражений.Это позволяет средству проверки типов статически проверять большинство границ массива.
Другой пример зависимого типа появляется в модульных системах для ML.Модули и их сигнатуры (также называемые интерфейсами) похожи на выражения и типы, но вместо описания вычислений они описывают структуру программы.
Зависимые типы очень часто встречаются в языкахэто не языки программирования в том смысле, в котором большинство программистов распознают, а языки для доказательства математических свойств программ (или просто математические теоремы).Большинство примеров на странице википедии имеют такую природу.
¹ В более общем смысле теоретики типов классифицируют системы типов в соответствии с тем, имеют ли они типы высшего порядка (типы, параметризованные типами), полиморфизм (выражения, параметризованные типами) и зависимые типы (типы, параметризованные выражениями). Эта классификация называется куб Барендрегта или лямбда-куб . Фактически это гиперкуб, но обычно четвертое измерение (выражения, параметризованные выражениями, то есть функциями) само собой разумеется.