#prolog #lambda-prolog
#пролог #лямбда-пролог
Вопрос:
Голландский математик Николас Говерт де Брейн изобрел эти индексы для представления терминов лямбда-исчисления без присвоения имен связанным переменным. Давайте возьмем это лямбда-выражение:
K = λx.λy.x
При использовании индексов де Брейна, когда мы используем соглашение, как здесь, читается, что нулевой индекс де Брейна относится к первому охватывающему лямбда-связующему:
K = λλ1
Индекс де Брейна 1 относится ко второму лямбда-связующему
, включающему индекс де Брейна. Как можно было бы написать код Prolog для подстановки,
чтобы мы могли вычислить бета-сокращение, например:
Kab = a
Комментарии:
1. Я думаю, это должно быть довольно просто. В чем, по-видимому, проблема?
2. Что вы тогда берете?
3. Если вы определяете некоторые тесты, люди могут быть более склонны кодировать это.
4. Лучший тестовый пример находится в формате PDF:
Ответ №1:
Индексы Де Брейна — это инструмент для настройки, где подстановка сложнее, чем в Prolog. Логические переменные — превосходный инструмент. Я не думаю, что вам когда-нибудь захочется писать код Prolog для работы с индексами де Брейна. (Мета-вопросы к вам ниже.)
В любом случае, вторая страница PDF-файла, связанного с вопросом, содержит реализацию Prolog всего, что необходимо. Он просто использует нестандартный, так называемый «функциональный» синтаксис.
Вот отношение сдвига в правильном синтаксисе:
funny_arrow(I, C, Term, Shifted) :-
( number(Term)
-> ( Term < C
-> Shifted = Term
; Shifted is Term I )
; Term = lambda(E)
-> Shifted = lambda(Shifted1),
C1 is C 1,
funny_arrow(I, C1, E, Shifted1)
; Term = apply(E1, E2)
-> Shifted = apply(Shifted1, Shifted2),
funny_arrow(I, C, E1, Shifted1),
funny_arrow(I, C, E2, Shifted2) ).
И вот подстановка:
substitute(Term, E, M, Substituted) :-
( number(Term)
-> ( Term = M
-> Substituted = E
; Substituted = Term )
; Term = lambda(E1)
-> Substituted = lambda(E1Subst),
funny_arrow(1, 0, E, EShifted),
M1 is M 1,
substitute(E1, EShifted, M1, E1Subst)
; Term = apply(E1, E2)
-> Substituted = apply(E1Subst, E2Subst), % typo in original?
substitute(E1, E, M, E1Subst),
substitute(E2, E, M, E2Subst) ).
Вы можете расшифровать правило бета-редукции таким же образом.
Затем мы можем это протестировать. На веселом языке, используемом в PDF, каждый базовый термин должен быть закодирован как числа, поэтому мы будем кодировать a
как 123
и b
как 456
произвольно. Сокращение термина (K a) b
будет выполнено путем уменьшения применения двух шагов сокращения, сначала для уменьшения K a
до KA
, а затем для применения KA
к b
. Вот так:
?- K = lambda(lambda(1)),
A = 123,
B = 456,
reduce(apply(K, A), KA),
reduce(apply(KA, B), KAB).
K = lambda(lambda(1)),
A = KAB, KAB = 123,
B = 456,
KA = lambda(124).
Результат KAB
такой же, как A
. Вы можете получить то же самое проще и эффективнее, определив:
apply(lambda(X, E), X, E).
и затем:
?- K = lambda(X, lambda(Y, X)),
apply(K, a, KA),
apply(KA, b, KAB).
K = lambda(a, lambda(b, a)),
X = KAB, KAB = a,
Y = b,
KA = lambda(b, a).
Вы, конечно, это знаете.
Мета: Ваши вопросы о кодировании неясных тем из символьной логики не получают большого отклика. Отчасти это связано с тем, что большинство из них не очень интересны. Отчасти это связано с тем, что им не хватает всех деталей и демонстрации каких-либо усилий с вашей стороны. Но я думаю, что третья часть заключается в том, что сообщество не понимает, в чем весь смысл этих вопросов. Не секрет, что вы опытный программист и разработчик Prolog. Очевидно, что вы можете записать несколько простых уравнений в Prolog. Так зачем спрашивать об этом других? Предполагается ли, что это какой-то проект по созданию «вики сообщества» или базы данных реализаций стандартных символьных алгоритмов в Prolog? Это может быть даже интересно, но вы, вероятно, привлекли бы больше участников к проекту, если бы сообщили, что проект существует, и чего он должен достичь.
Комментарии:
1. «Вы пробовали пример из PDF?» Этот пример?
?- reduce(apply(lambda(lambda(apply(1, 2))), 1), Reduced). Reduced = lambda(apply(2, 1)).
Да, это работает.2. Если вы опубликуете реализацию обратного преобразования с индексами де Брейна, включая некоторые тестовые примеры, демонстрирующие сложные проблемы с захватом переменных, у меня может возникнуть соблазн опубликовать реализацию без индексов де Брейна.
Ответ №2:
Я придумал другой подход, который ориентирован на линейную логику. Это означает, что он позволяет избежать вызова funny_arrow/4 внутри substitute/4 при каждом посещении связующего. Вот тестовый пример:
/* example from PDF */
?- apply(b(b(1*2)), 1, X).
X = b(2*1).
Исходный код выглядит следующим образом. Также исправляю опечатку в PDF, но с заглавной буквы, что funny_arrow/4 может принимать не только -1 и 1, но и другие значения:
Внимание, приведенный ниже код не является устойчивым!
% apply( Expr, Expr, -Expr)
apply(b(R), S, T) :-
subst(R, 0, S, T).
% subst( Expr, Integer, Expr, -Expr)
subst(P*Q, J, D, R*S) :- !,
subst(P, J, D, R),
subst(Q, J, D, S).
subst(b(P), J, D, b(R)) :- !,
K is J 1,
subst(P, K, D, R).
subst(J, K, _, J) :- integer(J), J < K, !.
subst(0, 0, D, D) :- !.
subst(J, J, D, R) :- integer(J), !,
shift(D, 0, J, R).
subst(J, _, _, K) :- integer(J), !, K is J-1.
subst(I, _, _, I).
% shift( Expr, Integer, Integer, -Expr)
shift(P*Q, J, D, R*S) :- !,
shift(P, J, D, R),
shift(Q, J, D, S).
shift(b(P), J, D, b(R)) :- !,
K is J 1,
shift(P, K, D, R).
shift(J, K, _, J) :- integer(J), J < K, !.
shift(J, _, D, K) :- integer(J), !, K is J D.
shift(I, _, _, I).