Search code examples
prologfailure-slice

why prolog is entering infinite loop?


I made this code so basically, it detects if the array in the first argument is the reverse array in the second argument, it works well but when I want to have the reversed array for a giving array, first it gives me the right answer than if I do ";" to have another answer I expect to get false which is normal, but Prolog just enters an infinite loop.

here is my code :

rev([],[]).
rev([X|A],B):- append(C,[X],B), rev(A,C) .

and this is a test to explain the problem: enter image description here


?- rev([4,3,9,9],[9,9,3,4]).
true ;
false.

?- rev([4,3,9,9],[4,2,1,4]).
false.

?- rev([4,3,9,9],Result).
Result = [9, 9, 3, 4] ;
.
.
.

Waiting for Prolog. Close again to force termination.

Solution

  • First of all, is this such a big problem? From time to time you do not get a clear response from Prolog but instead it just loops. So sometimes it behaves like a runaway engine. Certainly not ideal. But it could be worse! In particular, if it would produce an incorrect answer. Like failing, when there are solutions.

    To understand why Prolog loops in your case, it helps to put some falsework into your program. By adding goals false. In this manner we will see just the real reason:

    rev([],[]) :- false.
    rev([X|A],B):- append(C,[X],B), false, rev(A,C).
    
    ?- rev([4,3,9,9],Result), false.
       loops.
    

    Such a program is called a . The nice property here is that if this failure slice loops, also your original program will loop. But often this slice is much smaller, so the error is easier to detect.

    In order to get rid of that looping, you need to modify something in the visible part. One possibility would be to exchange the two goals. This would make this query terminate. But then,

    rev([],[]) :- false.
    rev([X|A],B):- rev(A,C), false, append(C,[X],B).
    
    ?- rev(L, [9,9,3,4]), false.
       loops.
    

    So by just exchanging goals, things are not solved in general.

    To solve this for both cases, both lists have to be taken into account prior to the first goal.

    rev(Xs, Ys) :-
       rev(Xs, Ys, Ys).
    
    rev([], [], []).
    rev([X|Xs], Ys, [_|Zs]) :-
       rev(Xs, Xsr, Zs),
       append(Xsr,[X],Ys).
    

    So a third argument was added, which ensures that the length of Ys may influence termination.

    There are actually better more efficient ways to express this. But conceptually this solution is simpler to understand.