Пытался вывести Z-комбинатор и вместо этого получил другой
-
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)))