Can I get a recursive Prolog predicate having two arguments, called reverse, which returns the inverse of a list:
Sample query and expected result:
?- reverse([a,b,c], L). L = [c,b,a].
A recursive Prolog predicate of two arguments called
palindrome
which returns true if the given list is palindrome.Sample query with expected result:
?- palindrome([a,b,c]). false. ?- palindrome([b,a,c,a,b]). true.
Ad 1: It is impossible to define reverse/2
as a (directly edit thx to @repeat: tail) recursive predicate - unless you permit an auxiliary predicate.
Ad 2:
palindrome(X) :- reverse(X,X).
But the easiest way is to define such predicates with DCGs:
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].
There isn't an efficient way to define reverse/2
with a single recursive definition without using some auxiliary predicate. However, if this is nevertheless permitted, a simple solution which doesn't rely on any built-ins like append/3
(and should be applicable for most Prolog implementations) would be to use an accumulator list, as follows:
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
is the reversal predicate which simply 'delegates' to (or, wraps) the accumulator-based version called rev-acc/2
, which recursively adds elements of the input list into an accumulator in reverse order.
Running this:
?- rev([1,3,2,x,4],L).
L = [4, x, 2, 3, 1].
And indeed as @false has already pointed out (+1),
palindrome(X) :- rev(X,X).
Just for curiosity here goes a recursive implementation of reverse/2 that does not use auxiliary predicates and still reverses the list. You might consider it cheating as it uses reverse/2 using lists and the structure -/2 as arguments.
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).
reverse(1-[], Ys).
should fail, but it succeeds with Ys = 1.
Then, reverse(Xs, Ys), Xs = [1].
should succeed but fails. So you are not cheating, but simply implementing another procedure. We agree not to call this a predicate - I presume. –
Septime reverse(Xs, [1]).
Isn't that a proper input list? It succeeds with Xs = [1]-[].
–
Septime 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).
conca/3
is just a copy of append/3
which is ISO, palindrome/1
destructures the list for no gain whatsoever (except preventing empty lists from being palindromes for no reason), and equal/2
is no improvement on =/2
except that it is unnecessarily more limiting. "What's new isn't good and what's good isn't new." –
Languor © 2022 - 2024 — McMap. All rights reserved.