Рекурсивный предикат Пролога для реверса / палиндрома
Могу ли я получить рекурсивный предикат Prolog, имеющий два аргумента, называемый reverse, который возвращает инверсию списка:
Пример запроса и ожидаемый результат:
? - обратный ([a,b,c], L). L = [c,b,a].
Рекурсивный предикат Пролога с двумя аргументами
palindrome
который возвращает истину, если данный список является палиндромом.Пример запроса с ожидаемым результатом:
? - палиндром ([a,b,c]). ложный. ? - палиндром ([b,a,c,a,b]). правда.
4 ответа
Нет эффективного способа определить reverse/2
с одним рекурсивным определением без использования некоторого вспомогательного предиката. Однако, если это все же разрешено, простое решение, которое не зависит от каких-либо встроенных append/3
(и должно быть применимо для большинства реализаций Prolog) будет использовать список аккумуляторов, как показано ниже:
rev([],[]).
rev([X|Xs], R) :-
rev_acc(Xs, [X], R).
rev_acc([], R, R).
rev_acc([X|Xs], Acc, R) :-
rev_acc(Xs, [X|Acc], R).
rev/2
предикат обращения, который просто "делегирует" (или оборачивает) версию на основе аккумулятора, называемую rev-acc/2
, который рекурсивно добавляет элементы списка ввода в аккумулятор в обратном порядке.
Запуск этого:
?- rev([1,3,2,x,4],L).
L = [4, x, 2, 3, 1].
И действительно, как @false уже указал (+1),
palindrome(X) :- rev(X,X).
Объявление 1: невозможно определить reverse/2
как рекурсивный предикат (непосредственно отредактируйте thx в @repeat: tail) - если только вы не разрешите вспомогательный предикат.
Объявление 2:
palindrome(X) :- reverse(X,X).
Но самый простой способ - определить такие предикаты с помощью DCG:
iseq([]) --> [].
iseq([E|Es]) --> iseq(Es), [E].
reverse(Xs, Ys) :-
phrase(iseq(Xs), Ys).
palindrome(Xs) :-
phrase(palindrome, Xs).
palindrome --> [].
palindrome --> [E].
palindrome --> [E], palindrome, [E].
Просто для любопытства здесь идет рекурсивная реализация reverse/2, которая не использует вспомогательные предикаты и все же переворачивает список. Вы можете считать это мошенничеством, поскольку он использует reverse/2, используя списки и структуру -/2 в качестве аргументов.
reverse([], []):-!.
reverse([], R-R).
reverse(R-[], R):-!.
reverse(R-NR, R-NR).
reverse([Head|Tail], Reversed):-
reverse(Tail, R-[Head|NR]),
reverse(R-NR, Reversed).
conca([],L,L).
conca([X|L1],L2,[X|L3]):- conca(L1,L2,L3).
rev([],[]).
rev([X|Y],N):- rev(Y,N1),conca(N1,[X],N).
palindrome([X|Y]):- rev([X|Y],N),equal([X|Y],N).
equal([X],[X]).
equal([X|Y],[X|Z]):- equal(Y,Z).