Кодирование Чёрча ― способ представления при помощи лямбда-выражений данных, не являющихся функциями и переменными, например, натуральных чисел и других констант. Метод назван в честь Алонзо Чёрча, разработавшего лямбда-исчисление.
Поскольку в чистом (бестиповом) лямбда-исчислении, в отличие от многих формальных систем (где выделены в качестве термов, например, целые числа, булевы значения, пары), единственным примитивным типом являются функции, все остальные виды данных необходимо конструировать с использованием лямбда-выражений. Кодирование подразумевает соглашение о том, как определять те или иные примитивы; например, числа Чёрча — способ кодирования натуральных чисел, булеаны Чёрча — соглашение о кодировании логических значений, пары Чёрча — кодирование упорядоченных пар элементов, есть несколько способов закодировать списки.
Кодирование Чёрча, как правило, не используется для реализации примитивных типов данных в практических языках программирования из-за неэффективности, но при этом демонстрирует, что любые вычисления могут быть сведены исключительно к функциям и переменным в бестиповом лямбда-исчислении, а другие примитивные типы данных не обязательны.
В этой статье иногда используется сокращённая λ-нотация для абстракций,
, а также стандартные комбинаторы
и
.
Пары Чёрча
Пары Чёрча — соглашение о кодировании упорядоченных пар, то есть наборов (кортежей) из двух элементов. Пара величин
и
представляется функцией, которая ожидает как свой единственный аргумент некую функцию
, и применяет её к обоим элементам пары,
и
:

Здесь
выступает в роли функции-продолжения, или функции-обработчика двух величин из пары.
Функции
и
, возвращающие соответственно первый и второй элемент пары, а также функция
(два варианта, для примера), меняющая местами два элемента пары, определяются как:




Булеаны Чёрча
Булеаны Чёрча — представления булевых значений, то есть «истины» (
) и «лжи» (
) как выбора первого и второго аргумента соответственно:


Некоторые языки программирования, такие как Smalltalk и Pico, используют их в качестве модели реализации для булевой арифметики.
Такое определение позволяет использовать предикаты (функции, возвращающие логические значения) как условия в условных выражениях. Над
и
могут быть реализованы стандартные логические операторы (конъюнкция, дизъюнкция, отрицание, исключающее «или»:




Реализация тернарной условной операции:
.
Предикаты — функции, возвращающие логическое значение — реализуются естественным образом, как функции возвращающие Булеаны как результат.
Числа Чёрча
Число Чёрча, соответствующее натуральному числу
, определяется как функция от двух параметров
и
, последовательно применяющая
раз функцию
начиная с
— другими словами, число Чёрча отображает функцию
в её
-кратную само-композицию:


значит «не применять функцию
к
вообще»,
значит «применять функцию 1 раз»,
значит «применять функцию по цепочке 2 раза», и так далее:
| Число
|
Определение нумерала
|
Лямбда-выражение
|
|
|
|
|
|
|
|
|
|
|
|
|
| ⋮
|
⋮
|
⋮
|
|
|
|
Вычисления над числами Чёрча
Арифметические операции над числами можно выразить в лямбда-исчислении как функции над числами Чёрча.
Операция сложения, отображая тождество
, то есть
, определяется как:

Добавление единицы
выводится из сложения посредством
-редукции, полагая
:

Действительно, выполнить что-то на один раз больше значит выполнить это ещё один раз. Таково последующее число после любого данного числа. В частности,
и
-эквивалентны.
И наоборот, беря эту операцию за основу вместе с нулём, как в аксиомах Пеано, можно вывести операцию сложения из неё, повторяя её данное число раз, получая эквивалентное определение

Для умножения замечаем, что
кратное повторение функции
это
-кратное повторение
-кратно повторенной функции
,
:

Возведение в степень
это умножение на
, повторенное
раз,
; а тетрация
это повторное возведение в степень,
:

Значит для чисел Чёрча "энная степень" это просто
, т.е. само число, а "энная тетрация" это
, где
это стандартный комбинатор удвоения аргумента,
.
Число-предшественник выполняет данную ему функцию на один раз меньше, подменяя её первое применение функцией тождества, и используя её для всех последующих:

Для примера,
.
Вычитание числа
достигается повторным вычитанием единицы,
раз:

Подобным образом могли бы быть определены также и

Аналогично функции
определяются и другие функции, как например
, вычисляющая целочисленное деление на 2, или факториал,
, а также и более эффективная версия вычитания,


Примеры вычисления:
;
;
.
Предикаты для чисел Чёрча
Предикат
, возвращающий
, если его аргумент является числом Чёрча
, и
в ином случае, вводится таким образом:

Предикат
над числами Чёрча, который проверяет, меньше или равен его первый аргумент второму:

Из тождества
получается предикат проверки на равенство
:

Предикат «меньше» это

Числа по Скотту
Для сравнения, кодирование чисел по Скотту определено как[1]





Кодировка Скотта для каждого алгебраического типа данных напрямую соответствует его определению. Натуральные числа по Пеано — это суммарный тип данных с двумя вариантами, 0 и не-0:
.
Соответственно, числo по Скотту это функция, ожидающaя две функции-обработчика, по числу вариантов.
Число по Скотту являет собой уже совершённое сопоставление с образцом, и вызывает соответствующую функцию-обработчик в соответствии с тем, является ли оно нулём или нет. В случае нуля дополнительных данных нет, так что это не функция а просто некая величина
,
. В случае же не-нулевого числа, дополнительным данным явлается его предшествующее число, например
.
В то время как в кодировке Чёрча
, в кодировке Скотта
,
, и
. Соответственно и функции перевода в другой тип тоже разнятся,


Как видим, определение перевода чисел Скотта рекурсивно, и требует использования оператора неподвижной точки, или соответственного переопределения с использованием само-применения, «вручную»:

Сложение определяется через повторение операции
, с использованием явной рекурсии:


Так же с использованием явной рекурсии приходится определять и все остальные операции над числами Скотта:

Зато операция вычитания (и следовательно деления) в целом более проста чем в кодировании Чёрча, благодаря простоте операции
для чисел Скотта. Аналогично и предикаты равенства и «меньше чем» гораздо проще (в смысле сложности вычислений):

Списки
Неизменяемый список из упорядоченных элементов может быть закодирован одним из следующих способов: через создание каждого элемента списка из двух пар, через создание каждого элемента списка из одной пары, через функцию свёртки справа, с использованием кодирования Скотта.
Представление в виде двух пар
При представлении в виде пары первый элемент содержит первый элемент списка, а второй — «хвост» списка, содержащий все остальные элементы. Поскольку таким способом не может быть выражен пустой список, то используется дополнительная обёртка — первый элемент указывает, является ли список пустым, а второй элемент содержит пару из первого элемента списка и хвоста списка.
Базовые операции со списками в этой схеме кодирования можно выразить следующим образом[2]:
— пустой список;
— возвращает первый элемент пары, который и означает, является ли список пустым;
— конструирует новый непустой список из первого элемента (головы списка)
и хвоста
;
— первый элемент пары во втором элементе — голова списка;
— второй элемент пары во втором элементе — хвост списка.
Используя эти функции можно определить остальные необходимые операции для списков, например, определение длины можно записать как:

хотя оно рекурсивно, что недопустимо в лямбда исчислении и требует дальнейшего применения комбинатора неподвижной точки. Возможно и более непосредственное определение, как

В пустом списке доступ ко второму элементу никогда не применяется, поскольку к нему не применимы понятия головы и хвоста списка.
Представление в виде одной пары
В качестве альтернативы списки можно определить следующим образом (
здесь соответствует пустому списку, непустые задаются парой головы и хвоста)[3]:

Здесь предикат
вызывает функцию-представление списка
с функцией продолжения, в качестве первого аргумента, которая получает два аргумента
и
, голову и хвост списка, в случае если список не пуст; и со значением
в качестве второго аргумента, которое будет возвращено, если список
пустой. Этот выбор уже произведен в момент создания значения
.
Обобщенный образец обработки таких списков это
. Соответственно, лучше определять

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

Здесь используются мнемонические имена переменных
для
(голова списка),
для
(хвост списка), и
для рекурсивного результата свертки хвоста списка.
Таким образом,
и
. Функция
определена таким же путём что и функция
для чисел Чёрча — передачей комбинирующей функции вперёд по цепочке после её одноразовой замены в самом начале на функцию пропускающую самый первый элемент (и соотвестственно, одноразовой замены данной функции
на функцию тождества в случае чисел Чёрча, для выполнения операции
на один раз меньше).
Легко определяются добавочные функции, как например:

Итак списки Чёрча — это функции свёртки, и операция
это тождественная функция (
свёртывает список составленный из эндофункций). Числа же по Чёрчу (как видно и из определения
) — это свертка справа унарного представления натуральных чисел, то есть списка из неразличимых, неинтересных элементов, длиной равной величине числа. Поэтому
соответствует функции
, а
соответствует
, с исключением аргумента
в обоих случаях.
Списки по Скотту
Ещё одним альтернативным представлением является представление списков через кодирование Скотта, которое использует идеи продолжения и сопоставления с образцом, и может привести к упрощению программного кода[4], а может и к усложнению.
Списки — это суммарный тип данных с двумя вариантами. В соответствии с общими принципами кодировки Скотта, каждый список представлен функцией которая ожидает два аргумента, две функции-получателя соответствующие этим двум вариантам: одна для варианта пустого списка и другая для непустого. Функция для непустого варианта получит головной элемент и хвост, а для пустого никаких данных нет, так что это не функция а просто величина:

Таким образом каждая величина в кодировке Скотта представляет собой результат уже произведённого сопоставления с образцами соответствующего типа данных. Например, величина
заключает в себе уже произведённый выбор варианта — получив
и
, она проигнорирует
и вызовет
с соответствующими данными,
и
.
Как числа по Чёрчу соответствуют спискам по Чёрчу с игнорированием их элементов, так же и для кодировок Скотта.
В отличие от кодирования Чёрча, которое, будучи сверткой, уже содержит в себе рекурсию для рекурсивных типов, кодирование Скотта игнорирует рекурсивность и представляет любые типы с одинаковым подходом, просто отображая их внешнюю структуру. Поэтому в отличие от списков Чёрча где мы передаём списку новую функцию свёртки и всю работу выполняет он сам, рекурсивные функции для списков Скотта проходится кодировать с явной рекурсией:

Примечания
- ↑ History of Lambda-calculus and Combinatory Logic, 2006, by Felice Cardone and J. Roger Hindley, p. 18, note 38
- ↑ Pierce, Benjamin C.. Types and Programming Languages. — MIT Press, 2002. — С. 500. — ISBN 978-0-262-16209-8.
- ↑ Tromp, John. 14. Binary Lambda Calculus and Combinatory Logic // Randomness And Complexity, From Leibniz To Chaitin (англ.) / Calude, Cristian S.. — World Scientific, 2007. — P. 237—262. — ISBN 978-981-4474-39-9.
As PDF: Tromp, John. Binary Lambda Calculus and Combinatory Logic (PDF) (14 мая 2014). Дата обращения: 24 ноября 2017. Архивировано 1 июня 2018 года.
- ↑ 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.
Литература