Несколько сотен шагов сокращения слишком много, чтобы получить нормальную форму Y fac ⌜3⌝?

9

Поскольку в последнее время я преподавал основы λ-исчисления, я реализовал простой инструмент оценки λ-исчисления в Common Lisp. Когда я задаю нормальную форму Y fac 3в обычном сокращении, требуется 619 шагов, что кажется немного большим.

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

fac = λfac.λn.if (= n 0) 1 (* n (fac (- n 1)))

В этом случае, принимая во внимание =, *а -также выделки функции, это займет всего около 50 шагов , чтобы получить Y fac 3к своей нормальной форме 6.

Но в моем оценщике я использовал следующее:

true = λx.λy.x
false = λx.λy.y
⌜0⌝ = λf.λx.x
succ = λn.λf.λx.f n f x
⌜n+1⌝ = succ ⌜n⌝
zero? = λn.n (λx.false) true
mult = λm.λn.λf.m (n f)
pred = λn.λf.λx.n (λg.λh.h (g f)) (λu.x) (λu.u)
fac = λfac.λn.(zero? n) ⌜1⌝ (* n (fac (pred n)))
Y = λf.(λf.λx.f (x x)) f ((λf.λx.f (x x)) f)

За 619 шагов я получаю от Y fac ⌜3⌝нормальной формы ⌜6⌝, а именно λf.λx.f (f (f (f (f (f x))))).

По быстрому просмотру множества шагов, я думаю, это определение predтребует столь длительного сокращения, но я все еще задаюсь вопросом, может ли это быть большой неприятной ошибкой в ​​моей реализации ...

РЕДАКТИРОВАТЬ: Первоначально я спросил о тысяче шагов, некоторые из которых действительно были вызваны неправильной реализацией нормального порядка, поэтому я сократил до 2/3 от первоначального количества шагов. Как прокомментировано ниже, с моей текущей реализацией, переключение с церковной арифметики на Пеано фактически увеличивает количество шагов ...

Нигде человек
источник

Ответы:

11

Церковное кодирование действительно плохо, если вы хотите использовать pred. Я бы посоветовал вам использовать более эффективное кодирование в стиле Peano:

// арифметика

: p_zero = λs.λz.z
: p_one = λs.λz.s p_zero
: p_succ = λn.λs.λz.sn
: p_null = λn.n (λx. ff) tt
: p_pred = λn.n (λp.p) p_zero
: p_plus = μ! f.λn.λm.n (λp. p_succ (! fpm)) m
: p_subs = μ! f.λn.λm.n (λp. p_pred (! fpm)) м
: p_eq = μ! f.λm.λn. m (λp. n (λq.! fpq) ff) (n (λx.ff) tt)
: p_mult = μ! f.λm.λn. m (λp. p_plus n (! fpn)) p_zero
: p_exp = μ! f.λm.λn. m (λp. p_mult n (! fpn)) p_one
: p_even = μ! f.λm. m (λp. not (! fp)) tt

// числа

: p_0 = λs.λz.z
: p_1 = λs.λz.s p_0
: p_2 = λs.λz.s p_1
: p_3 = λs.λz.s p_2
...

Это некоторый код, взятый из одной из моих старых библиотек, и μ!f. …это просто оптимизированная конструкция для Y (λf. …). (И tt, ff, notявляются булевыми.)

Я не совсем уверен, что вы получите лучшие результаты, facхотя.

Стефан Хименес
источник
Спасибо за совет, работа с этой альтернативной кодировкой помогла мне найти несколько ошибок в моей реализации. На самом деле, это не помогает для количества шагов, потому что после исправления, найти нормальную форму 3! делает 619 шагов с церковными цифрами и 687 с цифрами Пеано ...
Нигде человек
Да, это то, что я подумал, потому что использование какого-то специального правила редукции для Yздесь, кажется, крайне важно (особенно для чисел Пеано) для получения коротких сокращений.
Стефан Гименес
Просто любопытно, а как же 4 !, 5 !, 6! ?
Стефан Гименес
1
Как ни странно, после 3 !, кодирование Пеано становится более эффективным, чем кодирование Черча. Чтобы получить нормальную форму соответственно 1 !, 2 !, 3 !, 4! и 5! с Пеано / Церковью требуется шаги 10/10, 40/33, 157/134, 685/667, 3541/3956 и 21629/27311. Приблизительное количество шагов для 6! путем интерполяции из предыдущих данных оставлено в качестве упражнения для читателя.
Нигде человек
1
Представляется, что вышеупомянутые цифры Скотта являются именно «Пеано + λ = Скотт». Еще стоит попробовать их двоичные варианты (как для Черча, так и для <strike> Пеано </ strike> Скотта).
Стефан Гименес
2

Если я думаю о том, сколько операций ЦП делает для вычисления факториала 3, скажем, в Python, то несколько сотен сокращений не имеют большого значения.

Андрей Бауэр
источник