Церковная кодировка

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

Термины, которые обычно считаются примитивными в других обозначениях (таких как целые числа, логические значения, пары, списки и тегированные объединения), сопоставляются с функциями более высокого порядка в кодировке Чёрча. Тезис Чёрча -Тьюринга утверждает, что любой вычислимый оператор (и его операнды) может быть представлен в кодировке Чёрча. [ сомнительно ] В нетипизированном лямбда-исчислении единственным примитивным типом данных является функция.

Используйте [ править ]

Простая реализация кодирования Чёрча замедляет некоторые операции доступа из к , где — это размер структуры данных, что делает кодирование Чёрча непрактичным. [1] Исследования показали, что эту проблему можно решить путем целенаправленной оптимизации, но большинство функциональных языков программирования вместо этого расширяют свои промежуточные представления, чтобы они содержали алгебраические типы данных . [2] Тем не менее, кодирование Чёрча часто используется в теоретических аргументах, поскольку оно является естественным представлением для частичной оценки и доказательства теорем. [1] Операции можно типизировать с использованием типов более высокого ранга . [3] и примитивная рекурсия легко доступна. [1] Предположение о том, что функции являются единственными примитивными типами данных, упрощает многие доказательства.

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

Церковные цифры [ править ]

Числа Чёрча представляют собой натуральные числа в кодировке Чёрча. Функция высшего порядка , представляющая натуральное число n, — это функция, отображающая любую функцию к его n- кратному составу . Проще говоря, «значение» числа эквивалентно тому, сколько раз функция инкапсулирует свой аргумент.

Все числительные Чёрча представляют собой функции, принимающие два параметра. Числа Чёрча 0 , 1 , 2 , ... определяются в лямбда-исчислении следующим образом .

Начиная с 0, когда функция вообще не применяется, перейдите к 1, применяя функцию один раз, 2, применяя функцию дважды, 3 применяя функцию три раза и т. д .:

Цифра Чёрча 3 представляет собой действие трёхкратного применения любой заданной функции к значению. Предоставленная функция сначала применяется к предоставленному параметру, а затем последовательно к ее собственному результату. Конечным результатом не является цифра 3 (если только предоставленный параметр не равен 0 и функция не является функцией-преемником ). Сама функция, а не ее конечный результат, является цифрой Чёрча 3 . Число Чёрча 3 означает просто сделать что-либо три раза. Это наглядная демонстрация того, что подразумевается под «три раза».

Расчет цифрами Чёрча [ править ]

Арифметические операции над числами могут быть представлены функциями над числами Чёрча. Эти функции могут быть определены в лямбда-исчислении или реализованы в большинстве функциональных языков программирования (см. преобразование лямбда-выражений в функции ).

Функция сложения использует личность .

Функция-преемник является β- эквивалентным .

Функция умножения использует личность .

Функция возведения в степень дается определением числительных Чёрча, . В определении заменить получить и,

что дает лямбда-выражение,

The функцию сложнее понять.

Числа Чёрча применяют функцию n раз. Функция-предшественница должна возвращать функцию, которая применяет свой параметр n — 1 раз. Это достигается путем создания контейнера вокруг f и x , который инициализируется таким образом, чтобы исключить применение функции в первый раз. См. предшественник для более подробного объяснения.

Функцию вычитания можно написать на основе функции-предшественницы.

Таблица функций цифр Чёрча [ править ]

Функция Алгебра Личность Определение функции Лямбда-выражения
Преемник ...
Добавление
Умножение
Возведение в степень [а]
Предшественник [б]

Вычитание [б] ( Монус ) ...

информация Примечание:

  1. ^ Эта формула представляет собой определение числа Чёрча n с .
  2. ^ Jump up to: Перейти обратно: а б В кодировке Чёрча

Вывод функции-предшественника [ править ]

Функция-предшественник, используемая в кодировке Чёрча:

.

Чтобы построить предшественника, нам нужен способ применения функции на 1 раз меньше. Число n применяет функцию f n раз к x . Функция-предшественница должна использовать цифру n , чтобы применить функцию n -1 раз.

Прежде чем реализовать функцию-предшественник, рассмотрим схему, которая оборачивает значение в функцию-контейнер. Мы определим новые функции, которые будут использоваться вместо f и x , называемые inc и init . Контейнерная функция называется value . В левой части таблицы показано число n, примененное к inc и init .

Общее правило повторения таково:

Если также есть функция для извлечения значения из контейнера (называемая Extract ),

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

Функция Samenum по своей сути бесполезна. Однако, поскольку inc делегирует вызов f своему аргументу-контейнеру, мы можем организовать так, чтобы при первом приложении inc получал специальный контейнер, который игнорирует его аргумент, позволяя пропустить первое применение f . Назовите этот новый начальный контейнер const . В правой части приведенной выше таблицы показаны расширения n inc const . Затем, заменив init на const в выражении для той же функции, мы получим функцию-предшественницу:

Как объясняется ниже, функции inc , init , const , value и extract могут быть определены как:

Что дает лямбда-выражение для pred as,

Контейнер значений [ править ]

Контейнер значений применяет функцию к своему значению. Это определяется,

так,

Инк [ править ]

Функция inc должна принимать значение, содержащее v , и возвращать новое значение, содержащее fv .

Пусть g будет контейнером значений,

затем,

так,

Извлечь [ править ]

Значение можно извлечь, применив функцию идентификации:

Используя Я ,

так,

Константа [ править ]

Для реализации pred функция init заменяется константой , которая не применяет f . Нам нужна константа , чтобы удовлетворить,

Что будет удовлетворено, если

Или как лямбда-выражение,

Другой способ определения пред [ править ]

Pred также можно определить с помощью пар:

Это более простое определение, но оно приводит к более сложному выражению для pred. Расширение для :

Дивизия [ править ]

Деление натуральных чисел может быть реализовано с помощью: [4]

Расчет требуется много бета-сокращений. Если сокращение не выполняется вручную, это не имеет большого значения, но желательно не выполнять этот расчет дважды. Самый простой предикат для проверки чисел — IsZero , поэтому учитывайте условие.

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

По желанию, это определение имеет единственный вызов . Однако в результате эта формула дает значение .

Эту проблему можно исправить, добавив 1 к n перед вызовом метода div . Тогда определение разделения таково:

div1 — это рекурсивное определение. может Y-комбинатор использоваться для реализации рекурсии. Создайте новую функцию под названием div by;

  • В левой части
  • В правой части

получить,

Затем,

где,

Дает,

Или в виде текста, используя \ вместо λ ,

divide = (\n.((\f.(\x.x x) (\x.f (x x))) (\c.\n.\m.\f.\x.(\d.(\n.n (\x.(\a.\b.b)) (\a.\b.a)) d ((\f.\x.x) f x) (f (c d m f x))) ((\m.\n.n (\n.\f.\x.n (\g.\h.h (g f)) (\u.x) (\u.u)) m) n m))) ((\n.\f.\x. f (n f x)) n))

Например, 9/3 представлено

divide (\f.\x.f (f (f (f (f (f (f (f (f x))))))))) (\f.\x.f (f (f x)))

Используя калькулятор лямбда-исчисления, приведенное выше выражение уменьшается до 3 в обычном порядке.

\f.\x.f (f (f (x)))

Числа со знаком [ править ]

Один простой подход к расширению чисел Чёрча до чисел со знаком — использовать пару Чёрча, содержащую цифры Чёрча, представляющие положительное и отрицательное значение. [5] Целочисленное значение представляет собой разницу между двумя цифрами Чёрча.

Натуральное число преобразуется в число со знаком:

Отрицание выполняется путем замены значений.

Целочисленное значение представляется более естественным, если одно из значений пары равно нулю. Функция OneZero достигает этого условия,

Рекурсию можно реализовать с помощью Y-комбинатора:

Плюс и минус [ править ]

Сложение определяется математически для пары следующим образом:

Последнее выражение переводится в лямбда-исчисление как:

Аналогично определяется вычитание:

предоставление,

Умножить и разделить [ править ]

Умножение может быть определено как:

Последнее выражение переводится в лямбда-исчисление как:

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

Затем divZ используется в следующей формуле, которая аналогична формуле умножения, но с заменой mul на divZ .

Рациональные и действительные числа [ править ]

Рациональные и вычислимые действительные числа также могут быть закодированы с помощью лямбда-исчисления. Рациональные числа могут быть закодированы как пара чисел со знаком. Вычислимые действительные числа могут быть закодированы с помощью ограничивающего процесса, гарантирующего, что отличие от действительного значения будет отличаться на число, которое можно сделать настолько малым, насколько нам нужно. [6] [7] Приведенные ссылки описывают программное обеспечение, которое теоретически можно перевести в лямбда-исчисление. После определения действительных чисел комплексные числа естественным образом кодируются как пара действительных чисел.

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

Перевод с другими представлениями [ править ]

Большинство реальных языков поддерживают машинные целые числа; и функции Church Unchurch преобразуют неотрицательные целые числа в соответствующие им числа Чёрча. Функции приведены здесь в Haskell , где \ соответствует λ лямбда-исчисления. Реализации на других языках аналогичны.

type Church a = (a -> a) -> a -> a

church :: Integer -> Church Integer
church 0 = \f -> \x -> x
church n = \f -> \x -> f (church (n-1) f x)

unchurch :: Church Integer -> Integer
unchurch cn = cn (+ 1) 0

Церковные логические значения [ править ]

Церковные логические значения — это кодировка Чёрча логических значений true и false. Некоторые языки программирования используют их в качестве модели реализации булевой арифметики; примерами являются Smalltalk и Pico .

Булеву логику можно рассматривать как выбор. Кодирование Чёрча истинного и ложного является функциями двух параметров:

  • true выбирает первый параметр.
  • false выбирает второй параметр.

Эти два определения известны как церковные логические значения:

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

вычисляет предложение then, если предикат-x оценивается как true , и предложение else, если предикат-x оценивается как false .

Поскольку true и false выбирают первый или второй параметр, их можно комбинировать для создания логических операторов. Обратите внимание, что существует несколько возможных реализаций not .

Несколько примеров:

Предикаты [ править ]

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

Следующий предикат проверяет, меньше ли первый аргумент второго или равен ему:

,

Из-за идентичности,

Проверка на равенство может быть реализована как:

Церковные пары [ править ]

Пары Чёрча — это кодировка Чёрча парного ( двухкортежного) типа. Пара представлена ​​как функция, принимающая аргумент функции. Когда ему дан аргумент, он применит его к двум компонентам пары. Определение в лямбда-исчислении следующее:

Например,

Список кодировок [ править ]

( Неизменяемый ) список создается из узлов списка. Основные операции в списке:

Функция Описание
ноль Создайте пустой список.
существовал Проверьте, пуст ли список.
минусы Добавьте заданное значение в (возможно, пустой) список.
голова Получите первый элемент списка.
хвост Получите остальную часть списка.

Ниже мы даем четыре различных представления списков:

  • Создайте каждый узел списка из двух пар (чтобы учесть пустые списки).
  • Создайте каждый узел списка из одной пары.
  • Представьте список, используя функцию сгиба вправо .
  • Представьте список, используя кодировку Скотта, которая принимает случаи выражения соответствия в качестве аргументов.

Две пары как узел списка [ править ]

Непустой список может быть реализован парой Черча;

  • Первый содержит голову.
  • Второй содержит хвост.

Однако это не дает представления пустого списка, поскольку нет «нулевого» указателя. Чтобы представить ноль, пара может быть обернута в другую пару, давая три значения:

  • Сначала — нулевой указатель (пустой список).
  • Второй. Первый содержит голову.
  • Second.Second содержит хвост.

Используя эту идею, основные операции со списками можно определить следующим образом: [8]

Выражение Описание
Первый элемент пары имеет значение true , что означает, что список имеет значение NULL.
Получите индикатор null (или пустой список).
Создайте узел списка, который не равен нулю, и присвойте ему заголовок h и конец t .
второе.первое — голова.
секунда.секунда — это хвост.

В нулевом узле доступ к секунде никогда не осуществляется, при условии, что заголовок и хвост применяются только к непустым спискам.

Одна пара как узел списка [ править ]

В качестве альтернативы определите [9]

где последнее определение является частным случаем общего

Представьте список, сгибая его вправо [ править ]

В качестве альтернативы кодированию с использованием пар Чёрча список можно закодировать, идентифицировав его с помощью функции сгиба вправо . Например, список из трех элементов x, y и z может быть закодирован функцией высшего порядка, которая при применении к комбинатору c и значению n возвращает cx (cy (czn)).

Этому списку может быть присвоен тип в системе F.

Представьте список, используя кодировку Скотта [ править ]

Альтернативным представлением является кодирование Скотта, которое использует идею продолжений и может привести к более простому коду. [10] (см. также кодировку Могенсена – Скотта ).

В этом подходе мы используем тот факт, что списки можно наблюдать с помощью выражения сопоставления с образцом. Например, используя Scala , если нотацию list обозначает значение типа List с пустым списком Nil и конструктор Cons(h, t) мы можем просмотреть список и вычислить nilCode в случае, если список пуст и consCode(h, t) когда список не пуст:

list match {
  case Nil        => nilCode
  case Cons(h, t) => consCode(h,t)
}

The list определяется тем, как он действует на nilCode и consCode. Поэтому мы определяем список как функцию, которая принимает такие nilCode и consCode в качестве аргументов, чтобы вместо приведенного выше совпадения с образцом мы могли просто написать:

Обозначим через n параметр, соответствующий nilCode и по c параметр, соответствующий consCode. Пустой список — это тот, который возвращает нулевой аргумент:

Непустой список с заголовком h и хвост t дается

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

Кодирование Скотта может быть выполнено в нетипизированном лямбда-исчислении, тогда как его использование с типами требует системы типов с рекурсией и полиморфизмом типов. Список с типом элемента E в этом представлении, который используется для вычисления значений типа C, будет иметь следующее определение рекурсивного типа, где '=>' обозначает тип функции:

type List = 
  C =>                    // nil argument
  (E => List => C) =>     // cons argument
  C                       // result of pattern matching

Список, который можно использовать для вычисления произвольных типов, будет иметь тип, C. Общий список [ нужны разъяснения ] в E тоже взял бы E в качестве аргумента типа.

См. также [ править ]

Ссылки [ править ]

  1. ^ Jump up to: Перейти обратно: а б с Транкон и Видеманн, Бальтасар; Парнас, Дэвид Лорхе (2008). «Табличные выражения и полное функциональное программирование». У Олафа Читиля; Золтан Хорват; Виктория Жок (ред.). Реализация и применение функциональных языков . 19-й международный семинар IFL 2007, Фрайбург, Германия, 27–29 сентября 2007 г. Пересмотренные избранные статьи. Конспекты лекций по информатике. Том. 5083. стр. 228–229. дои : 10.1007/978-3-540-85373-2_13 . ISBN  978-3-540-85372-5 .
  2. ^ Янсен, Ян Мартин; Купман, Питер ВМ; Пласмейер, Маринус Дж. (2006). «Эффективная интерпретация путем преобразования типов данных и шаблонов в функции». Нильссон, Хенрик (ред.). Тенденции функционального программирования. Том 7 . Бристоль: Интеллект. стр. 73–90. CiteSeerX   10.1.1.73.9841 . ISBN  978-1-84150-188-8 .
  3. ^ «Предшественник и списки не могут быть представлены в просто типизированном лямбда-исчислении» . Лямбда-исчисление и лямбда-калькуляторы . okmij.org.
  4. ^ Эллисон, Ллойд. «Целые числа лямбда-исчисления» .
  5. ^ Бауэр, Андрей. "Ответ Андрея на вопрос: "Представление отрицательных и комплексных чисел с помощью лямбда-исчисления" " .
  6. ^ «Точная действительная арифметика» . Хаскелл . Архивировано из оригинала 26 марта 2015 г.
  7. ^ Бауэр, Андрей (26 сентября 2022 г.). «Программное обеспечение для вычислений с вещественными числами» . Гитхаб .
  8. ^ Пирс, Бенджамин К. (2002). Типы и языки программирования . МТИ Пресс . п. 500. ИСБН  978-0-262-16209-8 .
  9. ^ Тромп, Джон (2007). «14. Бинарное лямбда-исчисление и комбинаторная логика» . В Калуде, Кристиан С. (ред.). Случайность и сложность: от Лейбница до Хайтина . Всемирная научная. стр. 237–262. ISBN  978-981-4474-39-9 .
    В формате PDF: Тромп, Джон (14 мая 2014 г.). «Двоичное лямбда-исчисление и комбинаторная логика» (PDF) . Проверено 24 ноября 2017 г.
  10. ^ Янсен, Ян Мартин (2013). «Программирование в λ-исчислении: от Черча до Скотта и обратно». В Ахтене, Питер; Купман, Питер В.М. (ред.). Красота функционального кода — очерки, посвящённые Ринусу Пласмейеру по случаю его 61-летия . Конспекты лекций по информатике. Том. 8106. Спрингер. стр. 168–180. дои : 10.1007/978-3-642-40355-2_12 .