Комбинатор с фиксированной точкой - Fixed-point combinator

В математике и информатике в целом фиксированная точка функции - это значение, которое функция отображает сама себе.

В комбинаторной логике для информатики комбинатор с фиксированной точкой (или комбинатор с фиксированной точкой ) - это функция высшего порядка, которая возвращает некоторую фиксированную точку своей функции аргумента, если таковая существует.

Формально, если функция f имеет одну или несколько неподвижных точек, то

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

Y комбинатор

В классическом нетипизированном лямбда-исчислении каждая функция имеет фиксированную точку.

Частной реализацией исправления является парадоксальный комбинатор Карри Y , представленный

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

Этот комбинатор можно использовать для реализации парадокса Карри . Суть парадокса Карри заключается в том, что нетипизированное лямбда-исчисление нецелесообразно как дедуктивная система, и комбинатор Y демонстрирует это, позволяя анонимному выражению представлять ноль или даже множество значений. Это противоречит математической логике.

Применительно к функции с одной переменной комбинатор Y обычно не завершается. Более интересные результаты получаются при применении комбинатора Y к функциям двух или более переменных. Вторая переменная может использоваться как счетчик или индекс. Результирующая функция ведет себя как цикл while или for в императивном языке.

При таком использовании комбинатор Y реализует простую рекурсию. В лямбда-исчислении невозможно сослаться на определение функции в теле функции. Рекурсия может быть достигнута только путем передачи функции в качестве параметра. Y комбинатор демонстрирует этот стиль программирования.

Комбинатор с фиксированной точкой

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

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

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

В нетипизированном лямбда-исчислении функция, к которой применяется комбинатор с фиксированной точкой, может быть выражена с использованием кодирования, например кодирования Черча . В этом случае определенные лямбда-термины (которые определяют функции) рассматриваются как значения. «Запуск» (бета-уменьшение) комбинатора с фиксированной точкой при кодировании дает лямбда-член для результата, который затем может быть интерпретирован как значение с фиксированной точкой.

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

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

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

Ценности и домены

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

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

Например, рассмотрим

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

Для математика лямбда-исчисления это является следствием определения лямбда-исчисления. Для программиста это означает, что бета-сокращение лямбда-члена будет бесконечным циклом, никогда не достигнув нормальной формы.

Функция против реализации

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

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

Что такое комбинатор?

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

Использование в программировании

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

Факториальная функция

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

Функция, принимающая себя в качестве параметра, есть

Это дает YF n как

Настройка дает

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

Комбинаторы с фиксированной точкой в ​​лямбда-исчислении

Y комбинатор, обнаруженный Haskell B. Curry , определяется как

Бета-сокращение этого дает:

(по определению Y )
(путем β-редукции λf: применено Y к g)
(путем β-редукции λx: применена левая функция к правой функции)
(по второму равенству)

Многократное применение этого равенства дает:

(Вышеприведенное равенство следует рассматривать как последовательность многошаговых β-редукций слева направо. Лямбда-член , как правило, не может быть β-редукцией к члену . Вместо этого можно интерпретировать знаки равенства как β-эквивалентности многоступенчатого β-редукции, позволяющего двигаться в обоих направлениях.)

Эквивалентное определение комбинатора с фиксированной точкой

Этот комбинатор с фиксированной точкой может быть определен как y , как в

Выражение для y может быть получено с использованием правил из определения выражения let . Во-первых, используя правило

дает

Кроме того, используя

дает

А затем, используя правило сокращения эта ,

дает

Вывод комбинатора Y

Комбинатор Y Карри легко получить из определения y .

Начиная с,

Лямбда-абстракция не поддерживает ссылку на имя переменной в применяемом выражении, поэтому x необходимо передать в качестве параметра переменной x . Мы можем думать об этом как о замене x на xx , но формально это неверно. Вместо определения у по дает

Выражение let можно рассматривать как определение функции y , где z - параметр. Создание экземпляра z как y в вызове дает

И поскольку параметр z всегда передает функцию y ,

Используя правило сокращения эта ,

дает

Выражение пусть может быть выражено в виде лямбда - абстракции ; с использованием

дает

Возможно, это простейшая реализация комбинатора с фиксированной точкой в ​​лямбда-исчислении. Однако одно бета-сокращение дает более симметричную форму Y-комбинатора Карри:

См. Также Перевод между let и лямбда-выражениями .

Другие комбинаторы с фиксированной точкой

В нетипизированном лямбда-исчислении комбинаторы с фиксированной точкой не особенно редки. На самом деле их бесконечно много. В 2005 году Майер Голдберг показал, что набор комбинаторов с фиксированной точкой нетипизированного лямбда-исчисления рекурсивно перечислим .

Y комбинатор может быть выражено в SKI-исчислении как

Простейший комбинатор с фиксированной точкой в ​​SK-исчислении, найденный Джоном Тромпом , - это

хотя учтите, что он не в нормальном виде, который длиннее. Этот комбинатор соответствует лямбда-выражению

Следующий комбинатор с фиксированной точкой проще, чем комбинатор Y, и β-сводится к комбинатору Y; его иногда называют самим комбинатором Y:

Другой распространенный комбинатор с фиксированной точкой - это комбинатор с фиксированной точкой Тьюринга (названный в честь его первооткрывателя Алана Тьюринга ):

Его преимущество в том, что бета-сокращается до , тогда как и только бета-сокращается до общего термина.

также есть простая форма вызова по значению:

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

Строгий комбинатор с фиксированной точкой

В языке строгого программирования комбинатор Y будет расширяться до переполнения стека или никогда не останавливаться в случае оптимизации хвостового вызова. Z комбинатор будет работать в строгих языках (называемых также стремятся языки, где применяются аппликативный порядок оценки). Z комбинатор имеет следующий аргумент , определенный явным образом , предотвращая расширение Z г в правой части определения:

а в лямбда-исчислении это эта-расширение комбинатора Y :

Нестандартные комбинаторы с фиксированной точкой

В нетипизированном лямбда-исчислении есть термы, которые имеют то же дерево Бёма , что и комбинатор с фиксированной точкой, то есть они имеют такое же бесконечное расширение λx.x (x (x ...)). Они называются нестандартными комбинаторами с фиксированной точкой . Любой комбинатор с фиксированной точкой также является нестандартным, но не все нестандартные комбинаторы с фиксированной точкой являются комбинаторами с фиксированной точкой, потому что некоторые из них не удовлетворяют уравнению, которое определяет «стандартные». Эти странные комбинаторы называются строго нестандартными комбинаторами с неподвижной точкой ; Примером может служить следующий комбинатор:

куда

Множество нестандартных комбинаторов с фиксированной точкой не рекурсивно перечислимо.

Реализация на других языках

(Комбинатор Y - это конкретная реализация комбинатора с фиксированной точкой в ​​лямбда-исчислении. Его структура определяется ограничениями лямбда-исчисления. Нет необходимости или полезно использовать эту структуру при реализации комбинатора с фиксированной точкой в ​​других языках. )

Ниже приведены простые примеры комбинаторов с фиксированной точкой, реализованных в некоторых парадигмах программирования .

Ленивая функциональная реализация

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

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

Строгая функциональная реализация

На строгом функциональном языке аргумент функции f заранее раскрывается, давая бесконечную последовательность вызовов:

.

Это может быть решено путем определения исправления с дополнительным параметром.

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" *)

Реализация императивного языка

Этот пример представляет собой слегка интерпретируемую реализацию комбинатора с фиксированной точкой. Класс используется для содержания функции исправления , называемой 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);

В императивно-функциональном языке, таком как Lisp , Scheme или Racket , Ландин (1963) предлагает использовать присвоение переменной для создания комбинатора с фиксированной точкой:

(define Y!
  (lambda (f-maker)
    ((lambda (f)
       (set! f (f-maker (lambda (x) (f x)))) ;; assignment statement
       f)
     'NONE)))

Используя лямбда-исчисление с аксиомами для операторов присваивания, можно показать, что Y! удовлетворяет тому же закону фиксированной точки, что и комбинатор Y вызова по значению:

Набор текста

В Системе F (полиморфное лямбда-исчисление) полиморфный комбинатор с фиксированной точкой имеет тип;

∀a. (A → a) → a

где a - переменная типа . То есть fix принимает функцию, которая отображает a → a и использует ее для возврата значения типа a.

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

В простом типизированном лямбда-исчислении комбинатору с фиксированной точкой Y нельзя присвоить тип, потому что в какой-то момент он будет иметь дело с подчленом самоприменения в соответствии с правилом приложения:

где имеет бесконечный тип . Фактически невозможно типизировать комбинатор с фиксированной точкой; в этих системах любая поддержка рекурсии должна быть явно добавлена ​​к языку.

Тип для комбинатора Y

В языках программирования, поддерживающих рекурсивные типы данных , можно ввести комбинатор Y, соответствующим образом учитывая рекурсию на уровне типа. Потребность в самостоятельном применении переменной x может быть устранена с помощью типа (Rec a), который определен как изоморфный (Rec a -> a).

Например, в следующем коде Haskell у нас есть Inи, outявляющиеся именами двух направлений изоморфизма, с типами:

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)))

Общая информация

Из - за фиксированную точку комбинаторы могут быть использованы для реализации рекурсии, можно использовать их для описания типов конкретных рекурсивных вычислений, таких как те , в фиксированной точке итерации , итерационных методах , рекурсивный присоединиться в реляционных базах данных , анализ потока данных , в первую и FOLLOW наборы нетерминалов в контекстно-независимой грамматике , транзитивном замыкании и других типах операций замыкания .

Функция, для которой каждый вход является фиксированной точкой, называется функцией идентичности . Формально:

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

Другие функции обладают особым свойством, согласно которому после однократного применения дальнейшие приложения не имеют никакого эффекта. Более формально:

Такие функции называются идемпотентными (см. Также Проекция (математика) ). Примером такой функции является функция, которая возвращает 0 для всех четных целых чисел и 1 для всех нечетных целых чисел.

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

где полученный член может сводиться только к самому себе и представляет собой бесконечный цикл.

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

Комбинатор Y позволяет определять рекурсию как набор правил перезаписи , не требуя встроенной поддержки рекурсии в языке.

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

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

Примечания

использованная литература

внешние ссылки