Search code examples
prologfailure-slice

Shifting a list to the left N times in Prolog


I'm trying to make a relation in Prolog shiftL(L1,N,L2) that shifts L1 to the left N times (rotationally), and the result is L2, so for example shiftL([1,2,3], 2, [3,1,2]) is true.

I tried the following:

shiftL([],N,[]).
shiftL([X|Xs],1,L) :- append(Xs,[X],L).
shiftL([X|Xs],N,L) :- N1 is N-1 , N=\=1 , shiftL(L1,N1,L) , append(Xs,[X],L1).

And it works great, but after giving me the result it always keeps doing something else and I get a stack overflow:

?- shiftL([1,2,3], 2, L).
L = [3, 1, 2] ;
ERROR: Out of global stack

And I have no idea what's causing that. I thought I covered the base case with the second line, and with the N=\=1 statement.

Thanks in advance for any help!


Solution

  • Here is the relevant program fragment ():

    shiftL([],N,[]) :- false.
    shiftL([X|Xs],1,L) :-
       append(Xs,[X],L), false.
    shiftL([X|Xs],N,L) :-
       N1 is N-1 ,
       N=\=1,
       shiftL(L1,N1,L), false,
       append(Xs,[X],L1).
    

    So essentially the goal append(Xs,[X],L) loops. And it loops because neither Xs nor L is a list - that is a list with fixed length. To see this, consider the recursive goal shiftL(L1,N1,L). As you can see in the fragment, L1 occurs nowhere else. It is thus an uninstantiated variable. And L is the variable from the query. So you need to make either L1 or L a list. Like by putting the hidden append(Xs,[X],L1) in front.

    There is another loop with:

    ?- shiftL([1,2,3],-1,L).
    

    I believe you can solve that problem yourself.

    For more examples how failure-slices can narrow down problems of non-termination, see .