Типы как лекарство от парадоксов

Как идея «уровней» убирает порочный круг и почему именно она называется теорией типов.

Теория типов (Рассела) — иерархия уровней, где каждый объект имеет тип, а выражение можно строить только при согласовании уровней: самоприменение запрещено.

Идея уровней

Чтобы убрать парадокс, Рассел в «Principia Mathematica» (1910) предложил расслоить вселенную на уровни. Индивиды — уровень 0. Множества индивидов — уровень 1. Множества множеств индивидов — уровень 2. И так далее. Главное правило: членом множества уровня n+1 могут быть только объекты уровня n. Спросить «содержит ли множество само себя» теперь нельзя: оно и его элементы живут на разных уровнях, выражение x принадлежит x попросту не типизируется.

уровень 0:  индивиды         a, b, c
уровень 1:  множества инд.   {a, b},  {c}
уровень 2:  множества мн-в   { {a,b}, {c} }

x принадлежит y  допустимо ТОЛЬКО если  тип(y) = тип(x) + 1
x принадлежит x  =>  тип(x) = тип(x) + 1  =>  невозможно

Расселово R = { x | x не принадлежит x } больше не строится: само выражение нарушает дисциплину уровней. Болезнь вылечена не запретом «постфактум», а тем, что больной текст невозможно даже записать в системе.

Почему это называется «типом»

Уровень объекта Рассел назвал его типом. Здесь рождается само слово в нашем смысле. Тип — это «слой», к которому принадлежит объект, и операции разрешены только при согласовании слоёв. Спустя полвека эта идея вернулась в программирование: Int и Int -> Int — разные «слои», и применять число как функцию нельзя ровно по той же причине, по которой нельзя x принадлежит x.

Демонстрация: дисциплина уровней на Python

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

def level_of(obj):
    # уровень = глубина вложенности множеств
    if not isinstance(obj, frozenset):
        return 0
    if len(obj) == 0:
        return 1
    return 1 + max(level_of(e) for e in obj)

def can_contain(container_level, element):
    return level_of(element) == container_level - 1

a = "a"                      # уровень 0
s1 = frozenset({a})          # уровень 1
print("уровень a  :", level_of(a))
print("уровень s1 :", level_of(s1))
print("s1 может содержать a? ", can_contain(level_of(s1), a))
print("s1 может содержать s1?", can_contain(level_of(s1), s1))  # запрещено

Вывод:

уровень a  : 0
уровень s1 : 1
s1 может содержать a?  True
s1 может содержать s1? False

Самовключение отвергается формально — выражение «s1 содержит s1» не проходит проверку уровней. Это та же идея, что отвергнет 5(3) в типизированном языке.

От Рассела к Чёрчу

Теория Рассела была громоздкой. В 1940 году Алонзо Чёрч соединил её с лямбда-исчислением и получил простое типизированное лямбда-исчисление — компактную систему, где типы приписываются функциям и значениям. Именно она — прямой предок систем типов в современных языках, и именно с неё мы начнём формальную часть курса.

Как работает под капотом

Лекарство от парадоксов работает структурно: система типов не «ловит» плохое выражение проверкой, а делает его невыводимым — для него нет ни одного правила, которое приписало бы ему тип. Хорошая система типов всегда устроена так, что опасные конструкции (самоприменение, бесконечный спуск) просто не имеют типа.

Частые ошибки

  • «Уровни — это про память». Нет, это про логическую согласованность: запрет смешивать объект и коллекцию объектов.
  • Считать, что типы только запрещают. Они задают язык допустимых построений; внутри уровней свобода полная.
  • Думать, что лечение бесплатно. Иерархия типов отвергает и некоторые безобидные самоссылки; поиск баланса между безопасностью и выразительностью идёт до сих пор.

Итоги

  • Расслоение вселенной на уровни (типы) делает самоприменение невыразимым — парадокс исчезает.
  • Уровень объекта Рассел назвал его типом; отсюда термин в нашем смысле.
  • Чёрч соединил типы с лямбда-исчислением — родилось STLC, предок современных систем типов.
  • Опасные конструкции лечатся тем, что становятся невыводимыми, а не запрещёнными постфактум.
Проверьте себя
1. Как иерархия уровней убирает парадокс Рассела?
AЗапрещает большие множества
BДелает самоприменение невыразимым: элемент и коллекция на разных уровнях
CУскоряет проверку
DУдаляет отрицание
2. Откуда в теорию типов пришло само слово «тип»?
AИз программирования 1970-х
BУровень объекта в теории Рассела назывался его типом
CИз физики
DИз лингвистики
3. Что сделал Алонзо Чёрч с теорией типов?
AОпроверг её
BСоединил с лямбда-исчислением, получив простое типизированное лямбда-исчисление
CЗаменил множествами
DУдалил типы