Текст:Эрик Мейер:ФП при помощи бананов, линз, конвертов и колючей проволоки

Материал из свободной русской энциклопедии «Традиция»
Перейти к навигации Перейти к поиску

Мы разработали исчисление для ленивого функционального программирования, которое основано на операторах рекурсии, связанных с определениями типов данных. Для этих операторов мы вывели несколько алгебраических законов, которые полезны в деле трансформации программ. Мы покажем, что все функции из статьи Бёрда (Bird) и Уодлера (Wadler) «Введение в функциональное программирование» могут быть выражены через эти операторы.

Введение[править | править код]

В ряду многих стилей и методологий разработки программ стиль «Squiggol», по нашему мнению, заслуживает внимания со стороны сообщества функционального программирования. Общая цель Squiggol'а заключается в вычислении программ по их спецификациям таким же образом, как математик вычисляет решение дифференциальных уравнений или использует арифметику для решения числовых задач.

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

Эта философия похожа на методологию структурного программирования для императивного программирования. Использование оператора goto запрещено в целях поддержки структурированности потока управления при помощи таких примитивов, как условные выражения и циклы, которые заменяют фиксированные применения оператора goto, что позволяет программам быть выполнимыми и даже элегантными. Для функционального программирования подобный вопрос заключается в выборе схемы рекурсии в качестве базиса для исчисления программ. Мы предложим несколько операторов рекурсии, которые естественно ассоциируются с определениями алгебраических типов данных. Далее доказывается некоторое количество общих теорем об этих операторах, что далее используется для трансформации программ и доказательства корректности этого процесса.

Бёрд (Bird) и Меертенс (Meertens) [4, 18] идентифицировали некоторые правила для нескольких определённых типов данных (наиболее известные — конечные списки), которые они потом использовали для вычисления решения для нескольких проблем программирования. При помощи внедрения исчисления в теорию категорий работу Бёрда и Меертенса можно обобщить для произвольных, индуктивно определённых алгебраических типов данных [17, 12]. Некоторое время назад рабочая группа Бэкхауза (Backhouse) [1] расширила исчисление на родственные системы взглядов, достигнув тем самым покрытия недетерминизма.

Независимо Патерсон (Paterson) [21] разработал исчисление для функциональных программ, схожее по содержанию, но очень отличающееся по форме (как многие австралийские живтоные) с работами, указанными ранее. Но на самом деле, если кто-нибудь «проберётся» через синтаксические различия, он увидит, что правила, выведенные Патерсоном, являются теми же и иногда более общими, нежели те, что используются адептами Squiggol'а.

Эта работа предлагает расширение теории в контексте ленивого функционального программирования, т. е. для нас нас тип является ω-cpo, и мы рассматриваем только непрерывные отображения между типами (другими словами, мы работаем с категорией CPO). Работа с категорией SET, как сделали, для примера, Малькольм (Malcolm) [17] и Хагино (Hagino) [14], обозначает, что конечные типы данных (определённые в виде начальных алгебр) и бесконечные типы данных (определённые как терминальные коалгебры) составляют два различных «мира». В этом случае невозможно определить по индукции такие функции (катаморфизмы), которые были бы применимы и для конечных типов, и для бесконечных, а потому произвольно рекурсивные определения недопустимы. Работа в категории CPO позволяет заключить, что носители начальных алгебр и терминальных коалгебр совпадают, и что в этом случае единый тип данных можно использовать и для конечных, и для бесконечных структур. Цена, которую необходимо заплатить за такое удобство, заключается в том, что и функции, и значения становятся неизбежными.

Тип «список»[править | править код]

Мы проиллюстрируем шаблоны рекурсии на примере специфического типа данных, называемого «списком» (основанном на префиксации). Таким образом, определения в этом разделе являются конкретизацией тех общих определений, которые будут даны в четвёртом разделе. Современные языки программирования позволяют определить списки над элементами типа A A примерно следующим образом:

A ::= N i l | C o n s ( A | | A ) A* ::= Nil | Cons (A || A*)

Рекурсивная структура этого определения применяется в тех случаях, когда создаются функции с типом A B A* \rightarrow B , разрушающие список; такие функции называются катаморфизмами (от греческого предлога κατα, обозначающего «вниз», как в слове «катастрофа»). Анаморфизмами называются функции с типом B A B \rightarrow A* (от греческого предлога ανα, обозначающего «наверх», как в слове «анаболизм»), такие функции генерируют список A A* из начального значения типа B B . Функции типа A B A \rightarrow B , дерево вызовов для которых похоже на сами списки, называются хиломорфизмами (из философии Аристотеля, где слово υλοσ обозначает «пыль» или «материя»).

Катаморфизмы[править | править код]

Пусть b B b \in B и A | | B B \oplus \in A||B \rightarrow B , в этом случае катаморфизм для списка есть функция h A B h \in A* \rightarrow B следующего вида:

  • h N i l = b h Nil = b
  • h ( C o n s ( a , a s ) ) = a ( h a s ) h (Cons (a, as)) = a \oplus (h as)

В нотации Бёрда и Уодлера [5] эта функция будет записана как h = f o l d r b ( ) h = foldr b (\oplus) . Мы записываем катаморфизмы при помощи заключения соответствующих компонентов в т. н. бабановые скобки:

h = ( | b , | ) h = (|b, \oplus|)

Анаморфизмы[править | править код]

Хиломорфизмы[править | править код]

Параморфизмы[править | править код]

Алгебраические типы данных[править | править код]

Функторы[править | править код]

Произведение[править | править код]

Сумма[править | править код]

Стрелка[править | править код]

Единица, константы[править | править код]

Поднятие[править | править код]

Секционирование[править | править код]

Правила для базовых комбинаторов[править | править код]

Разное[править | править код]

Рекурсивные типы[править | править код]

Схемы рекурсии[править | править код]

Правила вычисления программ[править | править код]

Катаморфизмы[править | править код]

Правило вывода[править | править код]

Свойство уникальности[править | править код]

Правило слияния[править | править код]

Инъективные функции — катаморфизмы[править | править код]

Катаморфизмы сохраняют строгость[править | править код]

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

Развёртка/свёртка[править | править код]
Аккумулирующие параметры[править | править код]

Анаморфизмы[править | править код]

Правило вывода[править | править код]

Свойство уникальности[править | править код]

Правило слияния[править | править код]

Сюръективные функции — анаморфизмы[править | править код]

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

Хиломорфизмы[править | править код]

Разбиение хиломорфизмов[править | править код]

Правило сдвига[править | править код]

Соответствующие ката- и анаморфизмы[править | править код]

Пример: отражение двоичных деревьев[править | править код]

Параморфизмы[править | править код]

Пример: создание параморфизма из ката- и анаморфизмов[править | править код]

Параметризованные типы[править | править код]

Отображения[править | править код]

Итеративное повышение[править | править код]

Факторизация отображений[править | править код]

Монады[править | править код]

Заключение[править | править код]

Литература[править | править код]