Комбинатор с фиксированной точкой
В комбинаторной логике информатики — комбинатор с фиксированной точкой (или комбинатор с фиксированной точкой ), [1] : стр. 26 — это функция высшего порядка (т. е. функция, которая принимает функцию в качестве аргумента ), которая возвращает некоторую фиксированную точку (значение, сопоставленное самому себе) своей функции-аргумента, если таковая существует.
Формально, если представляет собой комбинатор с фиксированной точкой, а функция имеет одну или несколько неподвижных точек, то является одной из этих неподвижных точек, т.е.
Комбинаторы с фиксированной точкой могут быть определены в лямбда-исчислении и в языках функционального программирования и предоставляют средства, позволяющие использовать рекурсивные определения .
Y-комбинатор в лямбда-исчислении [ править ]
В классическом нетипизированном лямбда-исчислении каждая функция имеет фиксированную точку. Конкретная реализация - это Хаскеля Карри , заданный формулой парадоксальный комбинатор Y [2] : 131 [примечание 1]
(Здесь мы используем стандартные обозначения и соглашения лямбда-исчисления: Y — функция, которая принимает один аргумент f и возвращает все выражение после первой точки; выражение обозначает функцию, которая принимает один аргумент x , рассматриваемый как функция, и возвращает выражение , где обозначает x, примененный к самому себе. Сопоставление выражений обозначает применение функции, является левоассоциативным и имеет более высокий приоритет, чем точка.)
Проверка [ править ]
Следующий расчет подтверждает, что действительно является фиксированной точкой функции :
по определению путем β-редукции : замена формального аргумента f функции Y фактическим аргументом g путем β-редукции: замена формального аргумента x первой функции фактическим аргументом по второму равенству выше
Лямбда-терм вообще говоря, не может β-редуцироваться к члену . Однако, как показано, оба термина β-сводятся к одному и тому же термину.
Использует [ править ]
Применительно к функции с одной переменной комбинатор Y обычно не завершается. Более интересные результаты получаются при применении Y-комбинатора к функциям двух и более переменных. Дополнительные переменные могут использоваться в качестве счетчика или индекса. Полученная функция ведет себя как цикл while или for в императивном языке.
При таком использовании Y-комбинатор реализует простую рекурсию . Лямбда-исчисление не позволяет функции выступать в качестве термина в ее собственном определении, как это возможно во многих языках программирования, но функцию можно передать в качестве аргумента функции более высокого порядка, которая применяет ее рекурсивно.
Комбинатор Y также можно использовать для реализации парадокса Карри . Суть парадокса Карри заключается в том, что нетипизированное лямбда-исчисление некорректно как дедуктивная система, и комбинатор Y демонстрирует это, позволяя анонимному выражению представлять ноль или даже множество значений. Это противоречит математической логике.
Пример реализации [ править ]
Ниже представлен пример реализации Y-комбинатора на двух языках.
# Y Combinator in Python
Y = lambda f: (lambda x: f(x(x)))(lambda x: f(x(x)))
Y(Y)
// Y Combinator in C++, using C++ 14 extensions
int main() {
auto Y = [](auto f) {
auto f1 = [f](auto x) -> decltype(f) {
return f(x(x));
};
return f1(f1);
};
Y(Y);
}
Обратите внимание, что обе эти программы, хотя формально и корректны, на практике бесполезны; они оба выполняются бесконечно, пока не завершатся из-за переполнения стека . В более общем плане, поскольку и Python, и C++ используют строгие вычисления , комбинатор Y обычно бесполезен в этих языках; см. ниже комбинатор Z, который можно использовать в строгих языках программирования .
Комбинатор с фиксированной точкой [ править ]
Комбинатор Y — это реализация комбинатора с фиксированной точкой в лямбда-исчислении. Комбинаторы с фиксированной точкой также можно легко определить в других функциональных и императивных языках. Реализация лямбда-исчисления более сложна из-за ограничений лямбда-исчисления. Комбинатор с фиксированной точкой может использоваться в различных областях:
- Общая математика
- Нетипизированное лямбда-исчисление
- Типизированное лямбда-исчисление
- Функциональное программирование
- Императивное программирование
Комбинаторы с фиксированной точкой могут применяться к ряду различных функций, но обычно не завершаются, если нет дополнительного параметра. Когда функция, которую нужно исправить, ссылается на свой параметр, вызывается еще один вызов функции, поэтому вычисление никогда не начинается. Вместо этого дополнительный параметр используется для запуска начала расчета.
Тип фиксированной точки — это тип возвращаемого значения фиксируемой функции. Это может быть вещественное число, функция или любой другой тип.
В нетипизированном лямбда-исчислении функция, к которой применяется комбинатор с фиксированной точкой, может быть выражена с использованием кодировки, например кодировки Чёрча . В этом случае отдельные лямбда-термины (определяющие функции) рассматриваются как значения. «Запуск» (бета-уменьшение) комбинатора с фиксированной запятой при кодировании дает лямбда-терм для результата, который затем можно интерпретировать как значение с фиксированной запятой.
С другой стороны, функцию можно рассматривать как лямбда-терм, определенный исключительно в лямбда-исчислении.
Эти разные подходы влияют на то, как математик и программист могут относиться к комбинатору с фиксированной точкой. Математик может рассматривать Y-комбинатор, примененный к функции, как выражение, удовлетворяющее уравнению с фиксированной точкой, и, следовательно, как решение.
Напротив, человек, желающий применить комбинатор с фиксированной точкой только для какой-либо общей задачи программирования, может рассматривать его только как средство реализации рекурсии.
Ценности и домены [ править ]
Многие функции не имеют фиксированных точек, например с . Используя кодировку Чёрча , натуральные числа можно представить в лямбда-исчислении, и эту функцию f можно определить в лямбда-исчислении. Однако его домен теперь будет содержать все лямбда-выражения, а не только те, которые представляют натуральные числа. Комбинатор Y, примененный к f , даст фиксированную точку для f , но эта фиксированная точка не будет представлять собой натуральное число. При попытке вычислить Y f на реальном языке программирования произойдет бесконечный цикл.
Функция против реализации [ править ]
Комбинатор с фиксированной точкой может быть определен в математике, а затем реализован на других языках. Общая математика определяет функцию на основе ее экстенсиональных свойств. [3] То есть две функции равны, если они выполняют одно и то же отображение. Лямбда-исчисление и языки программирования рассматривают идентичность функции как интенсиональное свойство. Идентичность функции основана на ее реализации.
Функция лямбда-исчисления (или термин) представляет собой реализацию математической функции. В лямбда-исчислении существует ряд комбинаторов (реализаций), которые удовлетворяют математическому определению комбинатора с фиксированной точкой.
Определение термина «комбинатор» [ править ]
Комбинаторная логика — это теория функций высшего порядка . Комбинатор — это закрытое лямбда-выражение, то есть в нем нет свободных переменных . Комбинаторы можно комбинировать, чтобы направлять значения в правильные места в выражении, даже не называя их переменными.
определения и комбинаторы с точкой фиксированной Рекурсивные
Комбинаторы с фиксированной точкой можно использовать для реализации рекурсивного определения функций. Однако они редко используются в практическом программировании. [4] Строго нормализующие системы типов, такие как просто типизированное лямбда-исчисление, не допускают незавершения, и, следовательно, комбинаторам с фиксированной точкой часто не может быть присвоен тип или требуются сложные функции системы типов. Более того, комбинаторы с фиксированной точкой часто неэффективны по сравнению с другими стратегиями реализации рекурсии, поскольку они требуют большего сокращения функций, а также построения и разбора кортежа для каждой группы взаимно рекурсивных определений. [1] : стр. 232
Функция факториала [ править ]
Функция факториала представляет собой хороший пример того, как можно использовать комбинатор с фиксированной точкой для определения рекурсивных функций. Стандартное рекурсивное определение факториала в математике можно записать как
где n — неотрицательное целое число. Если мы хотим реализовать это в лямбда-исчислении, где целые числа представляются с использованием кодировки Чёрча , мы столкнемся с проблемой, заключающейся в том, что лямбда-исчисление не позволяет использовать имя функции («факт») в определении функции. Это можно обойти, используя комбинатор с фиксированной точкой. следующее.
Определите функцию F двух аргументов f и n :
(Здесь — это функция, которая принимает два аргумента и возвращает свой первый аргумент, если n = 0, и второй аргумент в противном случае; оценивается как n -1.)
Теперь определите . Затем является фиксированной точкой F , что дает
по желанию.
Комбинаторы с фиксированной точкой в лямбда-исчислении [ править ]
Комбинатор Y, открытый Хаскеллом Б. Карри , определяется как
Другие комбинаторы точкой фиксированной с
В нетипизированном лямбда-исчислении комбинаторы с фиксированной точкой не являются особенно редкими. На самом деле их бесконечно много. [5] В 2005 году Майер Голдберг показал, что множество комбинаторов с фиксированной точкой нетипизированного лямбда-исчисления является рекурсивно перечислимым . [6]
Комбинатор Y можно выразить в SKI-исчислении как
Дополнительные комбинаторы ( система B, C, K, W ) позволяют дать гораздо более короткое определение. С комбинатор для самостоятельного применения, поскольку и , вышеизложенное становится
Простейший комбинатор с фиксированной точкой в SK-исчислении, найденный Джоном Тромпом , — это
хотя учтите, что это не в обычном виде, который длиннее. Этот комбинатор соответствует лямбда-выражению
Следующий комбинатор с фиксированной точкой проще, чем Y-комбинатор, и β-сводится к Y-комбинатору; его иногда называют самим Y-комбинатором:
Другой распространенный комбинатор с фиксированной точкой — это комбинатор Тьюринга с фиксированной точкой (названный в честь его первооткрывателя Алана Тьюринга ): [7] [2] : 132
Его преимущество перед это что бета-редуцирует до , [примечание 2] тогда как и только бета-приведение к общему термину.
также имеет простую форму вызова по значению:
Аналогом взаимной рекурсии является поливариадный комбинатор с фиксированной точкой . [8] [9] [10] который можно обозначить Y*.
Строгий комбинатор с фиксированной точкой [ править ]
В строгом языке программирования Y-комбинатор будет расширяться до тех пор, пока не переполнится стек , или никогда не остановится в случае оптимизации хвостового вызова . [11] Z-комбинатор будет работать на строгих языках (также называемых нетерпеливыми языками, где применяется аппликативный порядок вычислений). В комбинаторе Z следующий аргумент определен явно, что предотвращает расширение в правой части определения: [12]
а в лямбда-исчислении это эта-расширение -комбинатора Y :
Нестандартные комбинаторы с фиксированной точкой [ править ]
Если F — комбинатор с фиксированной точкой в нетипизированном лямбда-исчислении, то мы имеем
Термы, которые имеют то же дерево Бема, что и комбинатор с фиксированной точкой, т. е. имеют такое же бесконечное расширение. , называются нестандартными комбинаторами с фиксированной точкой . Любой комбинатор с фиксированной точкой также является нестандартным, но не все нестандартные комбинаторы с фиксированной точкой являются комбинаторами с фиксированной точкой, поскольку некоторые из них не удовлетворяют уравнению с фиксированной точкой, которое определяет «стандартные». Эти комбинаторы называются строго нестандартными комбинаторами с фиксированной точкой ; примером является следующий комбинатор:
где
Множество нестандартных комбинаторов с фиксированной точкой не является рекурсивно перечислимым . [6]
Реализация на других языках [ править ]
Комбинатор Y — это частная реализация комбинатора с фиксированной точкой в лямбда-исчислении. Его структура определяется ограничениями лямбда-исчисления. Нет необходимости или пользы использовать эту структуру при реализации комбинатора с фиксированной точкой в других языках.
простые примеры комбинаторов с фиксированной точкой, реализованных в некоторых парадигмах программирования Ниже приведены .
Ленивая функциональная реализация [ править ]
В языке, поддерживающем отложенное вычисление , например, в Haskell , можно определить комбинатор с фиксированной точкой, используя определяющее уравнение комбинатора с фиксированной точкой, которое обычно называют fix
. Поскольку в Haskell есть ленивые типы данных, этот комбинатор также можно использовать для определения фиксированных точек конструкторов данных (а не только для реализации рекурсивных функций). Здесь дается определение, за которым следуют некоторые примеры использования. В Hackage исходный образец: [13]
fix, fix' :: (a -> a) -> a
fix f = let x = f x in x -- Lambda dropped. Sharing.
-- Original definition in Data.Function.
-- alternative:
fix' f = f (fix' f) -- Lambda lifted. Non-sharing.
fix (\x -> 9) -- this evaluates to 9
fix (\x -> 3:x) -- evaluates to the lazy infinite list [3,3,3,...]
fact = fix fac -- evaluates to the factorial function
where fac f 0 = 1
fac f x = x * f (x-1)
fact 5 -- evaluates to 120
Строгая функциональная реализация [ править ]
В строгом функциональном языке, как показано ниже на примере OCaml , аргумент f заранее расширяется, что дает бесконечную последовательность вызовов:
- .
Эту проблему можно решить, определив fix с помощью дополнительного параметра.
let rec fix f x = f (fix f) x (* note the extra x; here fix f = \x-> f (fix f) x *)
let factabs fact = function (* factabs has extra level of lambda abstraction *)
0 -> 1
| x -> x * fact (x-1)
let _ = (fix factabs) 5 (* evaluates to "120" *)
В мультипарадигмальном функциональном языке (наделенном императивными функциями), таком как Lisp , Питер Ландин предложил использовать присваивание переменных для создания комбинатора с фиксированной точкой, [14] как в примере ниже с использованием Scheme :
(define Y!
(lambda (f)
((lambda (i)
(set! i (f (lambda (x) (i x)))) ;; (set! i expr) assigns i the value of expr
i) ;; replacing it in the present lexical scope
#f)))
Используя лямбда-исчисление с аксиомами для операторов присваивания, можно показать, что Y!
удовлетворяет тому же закону фиксированной точки, что и комбинатор Y с вызовом по значению: [15] [16]
В более идиоматичном современном использовании Lisp это обычно обрабатывается с помощью метки с лексической областью действия (метки с лексической областью действия). let
выражение), поскольку лексическая область видимости не была введена в Лисп до 1970-х годов:
(define Y*
(lambda (f)
((lambda (i)
(let ((i (f (lambda (x) (i x))))) ;; (let ((i expr)) i) locally defines i as expr
i)) ;; non-recursively: thus i in expr is not expr
#f)))
Или без внутренней метки:
(define Y
(lambda (f)
((lambda (i) (i i))
(lambda (i)
(f (lambda (x)
(apply (i i) x)))))))
Императивная языковая реализация [ править ]
Этот пример представляет собой слегка интерпретирующую реализацию комбинатора с фиксированной точкой. Класс используется для хранения функции исправления , называемой fixer . Исправляемая функция содержится в классе, наследуемом от fixer. Функция fix обращается к функции, подлежащей исправлению, как к виртуальной функции. Что касается строгого функционального определения, fix явно задается дополнительный параметр x , что означает, что ленивая оценка не требуется.
template <typename R, typename D>
class fixer
{
public:
R fix(D x)
{
return f(x);
}
private:
virtual R f(D) = 0;
};
class fact : public fixer<long, long>
{
virtual long f(long x)
{
if (x == 0)
{
return 1;
}
return x * fix(x-1);
}
};
long result = fact().fix(5);
Набираю [ править ]
В Системе F (полиморфное лямбда-исчисление) полиморфный комбинатор с фиксированной точкой имеет тип [17]
- ∀а.(а → а) → а
где a — переменная типа . То есть fix принимает функцию, которая отображает a → a, и использует ее для возврата значения типа a.
В просто типизированном лямбда-исчислении, расширенном рекурсивными типами данных , можно писать операторы с фиксированной точкой, но тип «полезного» оператора с фиксированной точкой (того, приложение которого всегда возвращает результат) может быть ограничен.
В просто типизированном лямбда-исчислении комбинатору Y с фиксированной точкой нельзя присвоить тип [18] потому что в какой-то момент это будет касаться подтермина о самостоятельном применении по правилу применения:
где имеет бесконечный тип . На самом деле ни один комбинатор с фиксированной точкой не может быть напечатан; в этих системах любая поддержка рекурсии должна быть явно добавлена в язык.
Введите для Y-комбинатора [ править ]
В языках программирования, поддерживающих рекурсивные типы данных , можно ввести комбинатор Y, соответствующим образом учитывая рекурсию на уровне типа. Необходимостью самостоятельного применения переменной x можно управлять с помощью типа ( Rec a
), который определен так, чтобы быть изоморфным ( Rec a -> a
).
Например, в следующем коде Haskell у нас есть In
и out
это имена двух направлений изоморфизма с типами: [19] [20]
In :: (Rec a -> a) -> Rec a
out :: Rec a -> (Rec a -> a)
что позволяет нам написать:
newtype Rec a = In { out :: Rec a -> a }
y :: (a -> a) -> a
y = \f -> (\x -> f (out x x)) (In (\x -> f (out x x)))
Или то же самое в OCaml:
type 'a recc = In of ('a recc -> 'a)
let out (In x) = x
let y f = (fun x a -> f (out x x) a) (In (fun x a -> f (out x x) a))
Альтернативно:
let y f = (fun x -> f (fun z -> out x x z)) (In (fun x -> f (fun z -> out x x z)))
Общая информация [ править ]
Поскольку комбинаторы с фиксированной точкой могут использоваться для реализации рекурсии, их можно использовать для описания конкретных типов рекурсивных вычислений, например, итерации с фиксированной запятой , итеративных методов , рекурсивного соединения в реляционных базах данных , анализа потока данных , FIRST и СЛЕДУЙТЕ наборам нетерминалов в контекстно-свободной грамматике , транзитивном замыкании и других типах операций замыкания .
Функция, для которой каждый вход является фиксированной точкой, называется тождественной функцией . Формально:
В отличие от универсальной количественной оценки всех , комбинатор с фиксированной точкой создает одно значение, которое является фиксированной точкой . Замечательным свойством комбинатора с фиксированной точкой является то, что он строит неподвижную точку для произвольной заданной функции. .
Другие функции имеют особое свойство: после однократного применения дальнейшие применения не имеют никакого эффекта. Более формально:
Такие функции называются идемпотентными (см. также Проекция (математика) ). Примером такой функции является функция, которая возвращает 0 для всех четных целых чисел и 1 для всех нечетных целых чисел.
В лямбда-исчислении , с вычислительной точки зрения, применение комбинатора с фиксированной точкой к тождественной функции или идемпотентной функции обычно приводит к непрерывным вычислениям. Например, мы получаем
где результирующий член может сводиться только к самому себе и представляет собой бесконечный цикл.
Комбинаторы с фиксированной точкой не обязательно существуют в более ограничительных моделях вычислений. Например, их не существует в просто типизированном лямбда-исчислении .
Комбинатор Y позволяет рекурсию определить как набор правил перезаписи . [21] без необходимости встроенной поддержки рекурсии в языке. [22]
В языках программирования, поддерживающих анонимные функции , комбинаторы с фиксированной точкой позволяют определять и использовать анонимные рекурсивные функции , т.е. без необходимости привязки таких функций к идентификаторам . В этом случае использование комбинаторов с фиксированной точкой иногда называют анонимной рекурсией . [примечание 3] [23]
См. также [ править ]
- Анонимная функция
- Итерация с фиксированной точкой
- Лямбда-исчисление # Рекурсия и фиксированные точки
- Лямбда лифтинг
- Пусть выражение
Примечания [ править ]
- ^ правила синтаксиса, приведенные в Lambda Calculus#Notation . В этой статье для сохранения круглых скобок используются
- ^
- ^ Эта терминология, по-видимому, во многом фольклорная , но она встречается в следующем:
- Трей Нэш, Accelerated C# 2008 , Apress, 2007, ISBN 1-59059-873-3 , с. 462—463. В основном взято из Уэса Дайера (см. следующий пункт). блога
- Анонимная рекурсия Уэса Дайера в C# , 2 февраля 2007 г., содержит по существу аналогичный пример, найденный в книге выше, но сопровождаемый дополнительным обсуждением.
Ссылки [ править ]
- ^ Jump up to: Перейти обратно: а б Пейтон Джонс, Саймон Л. (1987). Реализация функционального программирования (PDF) . Прентис Холл Интернэшнл.
- ^ Jump up to: Перейти обратно: а б Хенк Барендрегт (1985). Лямбда-исчисление – его синтаксис и семантика . Исследования по логике и основам математики. Том. 103. Амстердам: Северная Голландия. ISBN 0444867481 .
- ^ Селинджер, Питер. «Конспекты лекций по лямбда-исчислению (PDF)» . п. 6.
- ^ «Для тех из нас, кто не знает, что такое Y-комбинатор и чем он полезен…» Hacker News . Проверено 2 августа 2020 г.
- ^ Бимбо, Каталин (27 июля 2011 г.). Комбинаторная логика: чистая, прикладная и типизированная . ЦРК Пресс. п. 48. ИСБН 9781439800010 .
- ^ Jump up to: Перейти обратно: а б Гольдберг, 2005 г.
- ^ Алан Мэтисон Тьюринг (декабрь 1937 г.). " -функция в - -конверсия». Журнал символической логики . 2 (4): 164. JSTOR 2268281 .
- ^ «Многоликость комбинатора с фиксированной точкой» . okmij.org .
- ^ Поливариадный Y в чистом Haskell98. Архивировано 4 марта 2016 г. на Wayback Machine , lang.haskell.cafe, 28 октября 2003 г.
- ^ "рекурсия - комбинатор с фиксированной точкой для взаимно рекурсивных функций?" . Переполнение стека .
- ^ Бене, Адам (17 августа 2017 г.). «Комбинаторы с фиксированной запятой в JavaScript» . Студия Бене . Середина . Проверено 2 августа 2020 г.
- ^ «CS 6110 S17 Лекция 5. Рекурсия и комбинаторы с фиксированной точкой» (PDF) . Корнеллский университет . 4.1 Комбинатор CBV с фиксированной точкой.
- ^ Исходное определение в Data.Function .
- ^ Ландин, П.Дж. (январь 1964 г.). «Механическая оценка выражений». Компьютерный журнал . 6 (4): 308–320. дои : 10.1093/comjnl/6.4.308 .
- ^ Феллейзен, Матиас (1987). Лямбда-v-CS-исчисление . Университет Индианы.
- ^ Талкотт, Кэролин (1985). Сущность рома: теория интенсиональных и экстенсиональных аспектов вычислений типа Lisp (докторская диссертация). Стэнфордский университет.
- ^ Жирар, Жан-Ив (1986). «Система F типов переменных, пятнадцать лет спустя». Теоретическая информатика . 45 (2): 159–192. дои : 10.1016/0304-3975(86)90044-7 . МР 0867281 . См., в частности, стр. 180.
- ^ Введение в лямбда-исчисление. Архивировано 8 апреля 2014 г. в Wayback Machine.
- ^ Ветка списка рассылки Haskell о том, как определить Y-комбинатор в Haskell , 15 сентября 2006 г.
- ^ Геверс, Герман; Остынь, Джоп. О комбинаторах с фиксированной точкой и циклических комбинаторах в теории типов . CiteSeerX 10.1.1.158.1478 .
- ^ Дэниел П. Фридман , Маттиас Феллизен (1986). «Глава 9 - Лямбда Ultimate». Маленький Лиспер . Ассоциация научных исследований . п. 179. «В этой главе мы создали Y-комбинатор, который позволяет нам писать рекурсивные функции с одним аргументом без использования определения».
- ^ Майк Ваньер. «Y-комбинатор (небольшой возврат) или: как добиться успеха в рекурсии, не прибегая к рекурсии» . Архивировано из оригинала 22 августа 2011 г. «В более общем плане Y дает нам возможность получить рекурсию на языке программирования, который поддерживает первоклассные функции, но не имеет встроенной рекурсии».
- ^ The If Works , вывод Y-комбинатора , 10 января 2008 г.
- Вернер Клюге, Абстрактные вычислительные машины: взгляд на лямбда-исчисление , Springer, 2005, ISBN 3-540-21146-2 , стр. 73–77.
- Майер Голдберг, (2005) О рекурсивной перечислимости комбинаторов с фиксированной запятой , Отчет БРИКС RS-05-1, Орхусский университет
- Феллизен , Лекция о почему Ю. том , Матиас
Внешние ссылки [ править ]
- Теория рекурсии и радость , Манфред фон Тун (2002 г. или ранее)
- Лямбда-исчисление - заметки Дона Блахеты, 12 октября 2000 г.
- Y Combinator. Архивировано 23 марта 2009 г. в Wayback Machine.
- «Использование Y-комбинатора в Ruby»
- «Функциональное программирование на языке Ada».
- Код Розетты — Y-комбинатор