Кодирование Чёрча ― способ представления при помощи лямбда-выражений данных, не являющихся функциями и переменными, например, натуральных чисел и других констант. Метод назван в честь Алонзо Чёрча, разработавшего лямбда-исчисление.
Поскольку в чистом (бестиповом) лямбда-исчислении, в отличие от многих формальных систем (где выделены в качестве термов, например, целые числа, булевы значения, пары), единственным примитивным типом являются функции, все остальные виды данных необходимо конструировать с использованием лямбда-выражений. Кодирование подразумевает соглашение о том, как определять те или иные примитивы; например, числа Чёрча — способ кодирования натуральных чисел➤, булеаны Чёрча — соглашение о кодировании логических значений, пары Чёрча➤ — кодирование упорядоченных пар элементов, есть несколько способов закодировать списки➤.
Кодирование Чёрча, как правило, не используется для реализации примитивных типов данных в практических языках программирования из-за неэффективности, но при этом демонстрирует, что любые вычисления могут быть сведены исключительно к функциям и переменным в бестиповом лямбда-исчислении, а другие примитивные типы данных не обязательны.
В этой статье может быть использована сокращённая λ-нотация для абстракций, .
Пары Чёрча — соглашение о кодировании упорядоченных пар, то есть наборов (кортежей) из двух элементов. Пара величин и представляется функцией, которая ожидает как свой единственный аргумент некую функцию , и применяет её к обоим элементам пары, и :
Здесь выступает в роли функции-продолжения, или функции-обработчика двух величин из пары.
Функции и , возвращающие соответственно первый и второй элемент пары, а также функция (два варианта, для примера), меняющая местами два элемента пары, определяются как:
Булеаны Чёрча
Булеаны Чёрча — представления булевых значений, то есть «истины» () и «лжи» () как выбора первого и второго аргумента соответственно:
Некоторые языки программирования, такие как Smalltalk и Pico[англ.], используют их в качестве модели реализации для булевой арифметики.
Предикаты — функции, возвращающие логическое значение — реализуются естественным образом, как функции возвращающие Булеаны как результат.
Числа Чёрча
Число Чёрча, соответствующее натуральному числу , определяется как функция от двух параметров и , последовательно раз применяющая функцию начиная с — другими словами, число Чёрча отображает функцию в её -кратную композицию:
значит «не применять функцию к вообще», значит «применять функцию 1 раз» и так далее:
Число
Определение нумерала
Лямбда-выражение
⋮
⋮
⋮
Вычисления над числами Чёрча
Арифметические операции над числами можно выразить в лямбда-исчислении как функции над числами Чёрча.
Операция сложения, отображая тождество , то есть , определяется как:
Добавление единицы выводится из сложения посредством -редукции, полагая :
Для умножения замечаем, что -кратное повторение функции это -кратное повторение -кратно повторенной функции , :
Возведение в степень это умножение на , повторенное раз, :
Число-предшественник выполняет данную ему функцию на один раз меньше, подменяя её функцией тождества, один только раз, при первом применении:
Для примера, .
Вычитание числа достигается повторным вычитанием единицы, раз:
Похожим образом могли бы быть определены:
Аналогично функции определяются и другие функции, как например:
вычисляющие целочисленное деление на 2, и факториал (выполняющий, к примеру, ).
Предикаты для чисел Чёрча
Предикат , возвращающий , если его аргумент является числом Чёрча , и в ином случае, вводится таким образом:
Предикат над числами Чёрча, который проверяет, меньше или равен его первый аргумент второму:
Из тождества получается предикат проверки на равенство :
Предикат «меньше» это
Числа по Скотту
Для сравнения, кодирование чисел по Скотту определено как[1]
Соответственно, числo по Скотту это функция, ожидающaя две функции-обработчика, по числу вариантов.
Число по Скотту являет собой уже совершённое сопоставление с образцом, и вызывает соответствующую функцию-обработчик в соответствии с тем, является ли оно нулём или нет. В случае нуля дополнительных данных нет, так что это не функция а просто некая величина , . В случае же не-нулевого числа, дополнительным данным явлается его предшествующее число, например .
В то время как в кодировке Чёрча , в кодировке Скотта , , и . Соответственно и функции перевода в другой тип тоже разнятся,
Как видим, определение перевода чисел Скотта рекурсивно, и требует использования оператора неподвижной точки, или соответственного переопределения с использованием само-применения, «вручную»:
Сложение определяется через повторение операции , с использованием явной рекурсии:
Так же с использованием явной рекурсии приходится определять и все остальные операции над числами Скотта:
Зато операция вычитания (и следовательно деления) в целом более проста чем в кодировании Чёрча, благодаря простоте операции для чисел Скотта. Аналогично и предикаты равенства и «меньше чем» гораздо проще (в смысле сложности вычислений):
Списки
Неизменяемыйсписок из упорядоченных элементов может быть закодирован одним из следующих способов: через создание каждого элемента списка из двух пар, через создание каждого элемента списка из одной пары, через функцию свёртки справа, с использованием кодирования Скотта.
Представление в виде двух пар
При представлении в виде пары первый элемент содержит первый элемент списка, а второй — «хвост» списка, содержащий все остальные элементы. Поскольку таким способом не может быть выражен пустой список, то используется дополнительная обёртка — первый элемент указывает, является ли список пустым, а второй элемент содержит пару из первого элемента списка и хвоста списка.
Базовые операции со списками в этой схеме кодирования можно выразить следующим образом[2]:
— пустой список;
— возвращает первый элемент пары, который и означает, является ли список пустым;
— конструирует новый непустой список из первого элемента (головы списка) и хвоста ;
— первый элемент пары во втором элементе — голова списка;
— второй элемент пары во втором элементе — хвост списка.
Используя эти функции можно определить остальные необходимые операции для списков, например, определение длины можно записать как:
хотя оно рекурсивно, что недопустимо в лямбда исчислении и требует дальнейшего применения комбинатора неподвижной точки. Возможно и более непосредственное определение, как
В пустом списке доступ ко второму элементу никогда не применяется, поскольку к нему не применимы понятия головы и хвоста списка.
Представление в виде одной пары
В качестве альтернативы списки можно определить следующим образом ( здесь соответствует пустому списку, непустые задаются парой головы и хвоста)[3]:
Здесь предикат вызывает функцию-представление списка с функцией продолжения, в качестве первого аргумента, которая получает два аргумента и , голову и хвост списка, в случае если список не пуст; и со значением в качестве второго аргумента, которое будет возвращено, если список пустой. Этот выбор уже произведен, заранее, в момент создания значения .
Списки по Чёрчу
В качестве альтернативы кодированию с использованием пар, кодировка Чёрча отождествляет список с функцией которая осуществляет его свёртку справа. Например, список из трёх элементов , и представляется функцией , которая ожидает комбинирующую функцию и значение , и возвращает значение свёртки :
Здесь используются мнемонические имена переменных для (голова списка), для (хвост списка), и для рекурсивного результата свертки хвоста списка.
Таким образом, и . Функция определена таким же путём что и функция для чисел Чёрча — передачей комбинирующей функции вперёд по цепочке после её одноразовой замены в самом начале на функцию пропускающую самый первый элемент (и соотвестственно, одноразовой замены данной функции на функцию тождества в случае чисел Чёрча, для выполнения операции на один раз меньше).
Легко определяются добавочные функции, как например:
Итак списки Чёрча — это функции свёртки, и операция это тождественная функция ( свёртывает список составленный из эндофункций). Числа же по Чёрчу (как видно и из определения ) — это свертка справа унарного представления натуральных чисел, то есть списка из неразличимых, неинтересных элементов, длиной равной величине числа. Поэтому соответствует функции , а соответствует , с исключением аргумента в обоих случаях.
Списки — это суммарный тип данных с двумя вариантами. В соответствии с общими принципами кодировки Скотта, каждый список представлен функцией которая ожидает два аргумента, две функции-получателя соответствующие этим двум вариантам: одна для варианта пустого списка и другая для непустого. Функция для непустого варианта получит головной элемент и хвост, а для пустого никаких данных нет, так что это не функция а просто величина:
Таким образом каждая величина в кодировке Скотта представляет собой результат уже произведённого сопоставления с образцами соответствующего типа данных. Например, величина заключает в себе уже произведённый выбор варианта — получив и , она проигнорирует и вызовет с соответствующими данными, и .
Как числа по Чёрчу соответствуют спискам по Чёрчу с игнорированием их элементов, так же и для кодировок Скотта.
В отличие от кодирования Чёрча, которое, будучи сверткой, уже содержит в себе рекурсию для рекурсивных типов, кодирование Скотта игнорирует рекурсивность и представляет любые типы с одинаковым подходом, просто отображая их внешнюю структуру. Поэтому в отличие от списков Чёрча где мы просто передаём списку новую функцию свёртки и всю работу выполняет он сам, рекурсивные функции для списков Скотта проходится кодировать с явной рекурсией:
Примечания
↑History of Lambda-calculus and Combinatory Logic, 2006, by Felice Cardone and J. Roger Hindley, p. 18, note 38
↑Jansen, Jan Martin. Programming in the λ-Calculus: From Church to Scott and Back (англ.) // LNCS[англ.] : journal. — 2013. — Vol. 8106. — P. 168—180. — doi:10.1007/978-3-642-40355-2_12.