The following is a standard textbook definition of reverse(X,Y)
which is true if the list Y
is the reverse of the list X
. The code is often used to introduce or illustrate the use of an accumulator.
% recursive definition
step([], L2, L2).
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]).
% convenience property around step/3
reverse(X, Y) :- step(X, Y, []).
The following query works as expcted.
?- reverse([1,2,3], Y).
Y = [3,2,1]
But the following fails after it prompts to search for more solutions after the first one.
?- reverse(X, [1,2,3]).
X = [3,2,1]
Stack limit (0.2Gb) exceeded
Stack sizes: local: 3Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 4,463,497, last-call: 100%, Choice points: 12
...
Questions:
reverse(X,Y)
such that it is reversible, in the sense that both of the above queries work and terminate?step([], L2, L2):- !.
appears to work, but this seems like we've waded into procedural programming and have drifted far away from declarative logic programming. Is this a fair judgement?Yes, you have correctly noted that this predicate does not terminate when you pass a variable in the first argument. It also does not terminate if the first argument is a partial list.
step([], L2, L2).
, which is clearly the base case for your recursion/induction. When you ask the Prolog engine for additional witnesses, it proceeds by trying to do so using the induction rule step([H1|T1], X, L2) :- step(T1, X, [H1|L2])
. Note that your implementation here is defined recursively on the first argument, and so this unifies the unbound first argument with [H1|T1]
, and then makes a recursive call with T1
as the first argument, which then unifies with a fresh [H1|T1]
, which makes a recursive call... This is the cause of the infinite loop you're observing.reverse(X, Y) :- same_length(X, Y), step(X, Y, []).
This solves the problem for both of the queries you posed. As an added bonus, it's actually possible to pose the "most general query" and get a sensible infinite sequence of results with this definition:
?- reverse(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_] ;
X = [_A, _B],
Y = [_B, _A] ;
X = [_A, _B, _C],
Y = [_C, _B, _A] ;
X = [_A, _B, _C, _D],
Y = [_D, _C, _B, _A] ;
...