stringtranslate.com

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

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

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

Использовать

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

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

Церковные цифры

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

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

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

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

Расчет с помощью церковных цифр

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

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

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

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

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

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

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

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

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

Таблица функций над церковными числами

Примечания :

  1. ^ Эта формула является определением числа Чёрча n с .
  2. ^ ab В церковной кодировке,

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

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

.

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

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

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

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

Тогда extract может быть использован для определения функции samenum следующим образом:

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

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

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

Другой способ определения pred

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

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

Разделение

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

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

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

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

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

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

получить,

Затем,

где,

Дает,

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

делим = (\n.((\f.(\xx x) (\xf (xx))) (\c.\n.\m.\f.\x.(\d.(\nn (\x .(\a.\bb)) (\a.\ba)) d ((\f.\xx) fx) (f (cdmfx))) ((\m.\nn (\n.\f.\ xn (\g.\hh (gf)) (\ux) (\uu)) m) nm))) ((\n.\f.\x. f (nfx)) n))

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

делим (\f.\xf (f (f (f (f (f (f (f (f (fx))))))))) (\f.\xf (f (fx)))

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

\ф.\хф (ф (ф (х)))

Подписанные числа

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

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

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

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

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

Плюс и минус

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

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

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

давая,

Умножение и деление

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

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

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

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

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

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

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

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

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

тип Церковь а = ( а -> а ) -> а -> а          церковь :: Целое число -> Церковь Целое число церковь 0 = \ f -> \ x -> x церковь n = \ f -> \ x -> f ( церковь ( n - 1 ) f x )                       unchurch :: Церковь Целое число -> Целое число unchurch cn = cn ( + 1 ) 0           

Церковные булевы операторы

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

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

Эти два определения известны как булевы операторы Чёрча:

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

оценивается как then-clause, если predicate-x оценивается как true , и как else-clause, если predicate-x оценивается как false .

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

Вот несколько примеров:

Предикаты

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

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

,

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

Тест на равенство может быть реализован следующим образом:

Церковные пары

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

Например,

Список кодировок

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

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

Две пары как узел списка

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

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

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

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

Одна пара как узел списка

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

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

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

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

Этому списковому представлению можно присвоить тип в Системе F.

Представьте список с помощью кодировки Скотта

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

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

список совпадений { case Nil => nilCode case Cons ( h , t ) => consCode ( h , t ) }           

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

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

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

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

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

тип List = C => // аргумент nil ( E => List => C ) => // аргумент cons C // результат сопоставления с образцом               

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

Смотрите также

Ссылки

  1. ^ abc Trancón y Widemann, Baltasar; Parnas, David Lorge (2008). "Tabular Expressions and Total Functional Programming". В Olaf Chitil; Zoltán Horváth; Viktória Zsók (ред.). Implementation and Application of Functional Languages. 19-й международный семинар, IFL 2007, Фрайбург, Германия, 27–29 сентября 2007 г. Пересмотренные избранные статьи. Lecture Notes in Computer Science. Том 5083. С. 228–229. doi :10.1007/978-3-540-85373-2_13. ISBN 978-3-540-85372-5.
  2. ^ Янсен, Ян Мартин; Купман, Питер ВМ; Пласмейер, Маринус Дж. (2006). «Эффективная интерпретация путем преобразования типов данных и шаблонов в функции». В Нильссон, Хенрик (ред.). Тенденции в функциональном программировании. Том 7. Бристоль: Intellect. стр. 73–90. CiteSeerX 10.1.1.73.9841 . ISBN  978-1-84150-188-8.
  3. ^ «Предшественник и списки не могут быть представлены в простом типизированном лямбда-исчислении». Лямбда-исчисление и лямбда-калькуляторы . okmij.org.
  4. ^ Эллисон, Ллойд. «Лямбда-исчисление целых чисел».
  5. ^ Бауэр, Андрей. «Ответ Андрея на вопрос: «Представление отрицательных и комплексных чисел с помощью лямбда-исчисления»».
  6. ^ "Точная вещественная арифметика". Haskell . Архивировано из оригинала 2015-03-26.
  7. ^ Бауэр, Андрей (26 сентября 2022 г.). "Программное обеспечение для вычисления действительных чисел". GitHub .
  8. ^ Пирс, Бенджамин С. (2002). Типы и языки программирования . MIT Press . стр. 500. ISBN 978-0-262-16209-8.
  9. ^ Тромп, Джон (2007). "14. Двоичное лямбда-исчисление и комбинаторная логика". В Calude, Cristian S (ред.). Случайность и сложность, от Лейбница до Хайтина . World Scientific. стр. 237–262. ISBN 978-981-4474-39-9.
    В формате PDF: Тромп, Джон (14 мая 2014 г.). «Двоичное лямбда-исчисление и комбинаторная логика» (PDF) . Получено 24.11.2017 .
  10. ^ Янсен, Ян Мартин (2013). «Программирование в λ-исчислении: от Чёрча до Скотта и обратно». В Ахтен, Питер; Купман, Питер ВМ (ред.). Красота функционального кода — эссе, посвящённые Ринусу Пласмейеру по случаю его 61-го дня рождения . Конспект лекций по информатике. Том 8106. Springer. С. 168–180. doi :10.1007/978-3-642-40355-2_12.