Пытался вывести Z-комбинатор и вместо этого получил другой

cs.stackexchange https://cs.stackexchange.com/questions/128908

  •  29-09-2020
  •  | 
  •  

Вопрос

Я работал над созданием Z-комбинатора, начав с функции факториала, а в итоге получил другой комбинатор с фиксированной точкой.Что я вывел?Я допустил тонкую ошибку?

Вот шаги, которые я выполнил (в JavaScript)

1.Объявить функцию факториала

let fact = n =>
    n < 2 ? 1 : n * fact(n - 1)

2.Преобразовать в комбинатор (закрытое выражение)

let fact = (self, n) =>
    n < 2 ? 1 : n * self(n - 1)

3.Самовызов потока

Судя по подписи fact(?, 7), проходя fact поскольку первый аргумент кажется разумным fact(fact,7).Итак, пропустите параметр через хвостовой вызов:

let fact = (self, n) =>
    n < 2 ? 1 : n * self(self, n - 1)

Использование сейчас fact(fact,7)5040

4.Рефакторинг в каррированную форму

let fact = self =>
    n => n < 2 ? 1 : n * self(self)(n - 1)

5.Переместить собственное приложение в локальную декларацию

let fact = self => {
    let f = n => self(self)(n)
    return n => n < 2 ? 1 : n * f(n - 1)
}

6.Преобразование объявления let в лямбда-выражение

let fact = self =>
    (f =>
        n => n < 2 ? 1 : n * f(n - 1)
    )(
        n => self(self)(n)
    )

Использование по-прежнему fact(fact)(7)5040

7.Разделите выражение факториала

let _fact = f => n =>
    n < 2 ? 1 : n * f(n - 1)

let fact = self =>
    (
        _fact
    )(
        n => self(self)(n)
    )

8.Переместить самозаявление от звонящего в тело

let _fact =
    f => n => n < 2 ? 1 : n * f(n - 1)

let fact = (() => {
    let innerFact = self =>
        (
            _fact
        )(
            n => self(self)(n)
        )
    return innerFact(innerFact)
})()

Использование сейчас fact(7)5040

9.Преобразование объявления let в лямбда-выражение

let _fact =
    f => n => n < 2 ? 1 : n * f(n - 1)

let fact = (() => {
    return (
        innerFact => innerFact(innerFact)
    )(
        self => (_fact)(n => self(self)(n))
    )
})()

10.Упростить выражение

let _fact =
    f => n => n < 2 ? 1 : n * f(n - 1)

let fact =
    (innerFact => innerFact(innerFact))
    (self => (_fact)(n => self(self)(n)))

Санитарная проверка.Использование по-прежнему fact(7)5040

11.Переименовать переменные

Использование innerFact и self подозрительно похожи.Переименуйте ту же переменную, чтобы обнаружить закономерность.Отдельные лексические области так безопасно делать:

let _fact =
    f => n => n < 2 ? 1 : n * f(n - 1)

let fact =
    (u => u(u))
    (u => (_fact)(n => u(u)(n)))

12.Абстрактный _fact использование и переименование fact

Переименовать fact к setup и абстрактный _fact в теле, заменив параметром f

let _fact =
    f => n => n < 2 ? 1 : n * f(n - 1)

let setup = f =>
    (u => u(u))
    (u => (f)(n => u(u)(n)))

let fact = setup(_fact)

Нет необходимости в отдельном _fact объявление так встроено:

let setup = f =>
    (u => u(u))
    (u => (f)(n => u(u)(n)))

let fact = setup(
    f => n => n < 2 ? 1 : n * f(n - 1)
)

13.Переименовать setup

Переименовать его во что?Что это за комбинатор?В соответствии с Википедия Z-комбинатор:

let Z = f => 
    (u => f(v => u(u)(v)))
    (u => f(v => u(u)(v)))

Но я вывел следующее:

let setup = f =>
    (u => u(u))
    (u => (f)(n => u(u)(n)))

Определение fact с точки зрения любого из них кажется эквивалентным в поведении.Я допустил ошибку?Я случайно заново открыл для себя еще один известный комбинатор?

Это было полезно?

Решение

Если я встрою (u => (f)(n => u(u)(n))) в (u => u(u)) Я получил:

(u => f(n => u(u)(n)))
(u => f(n => u(u)(n)))

Это именно Z-Комбинатор.

Из Википедии:

let Z = f => 
    (u => f(v => u(u)(v)))
    (u => f(v => u(u)(v)))

Мой вывод:

let fix = f =>
    (u => f(n => u(u)(n)))
    (u => f(n => u(u)(n)))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с cs.stackexchange
scroll top