1

After loading the following program using SWI-Prolog and entering queries such as

cells([o,x,o,x,o], A).

or

cells(A, [o,x,o,x,o]).

the first result seems to always be correct, but after submitting semicolon to look for more results (and I don't know if there should be additional results in either case), I get a PROLOG SYSTEM ERROR mentioning garbage collection and an Out of global stack error respectively.

regla(o,o,o,o).
regla(x,o,o,x).
regla(o,x,o,o).
regla(o,o,x,x).
regla(x,o,x,x).
regla(x,x,o,x).
regla(o,x,x,x).
regla(x,x,x,o).

cells([X | XS], [Y | YS]) :-
    X = o,
    Y = o,
    length([X | XS], LX),
    LX >= 3,
    length([Y | YS], LY),
    LY is LX + 2,
    append([o, o], [X | XS], W),
    append(W, [o, o], Z),
    cellsR(Z, [Y | YS]).

cellsR(_, []).
cellsR([A, B, C | R], [H | T]) :-
    regla(A, B, C, H),
    cellsR([B, C | R], T).

I'm assuming that the errors have to do with the way I handle recursion, so maybe someone can have a look at the code and tell me where I'm going wrong.

false
  • 10,264
  • 13
  • 101
  • 209
luckysori
  • 23
  • 4

1 Answers1

5

My first advice: do not use a tracer. It will not help you a lot. Termination is much too complex than what a step-by-step tracer can show you. Let me give you the reason why your program does not terminate, first:

cells([X | XS], [Y | YS]) :-
    X = o,
    Y = o,
    length([X | XS], LX),
    LX >= 3,
    length([Y | YS], LY), false,
    LY is LX + 2,
    append([o, o], [X | XS], W),
    append(W, [o, o], Z),
    cellsR(Z, [Y | YS]).

This highlights the part of your program that you will have to modify to remove your problem. In other words, as long as you leave that part unchanged, your problem will not go away.

A minimal change is to add a further goal that establishes the relation between the length of those two lists first, before length/2 is used:

cells([X | XS], [Y | YS]) :-
    X = o,
    Y = o,
    list_samelength([_,_|XS], YS),
    length([X | XS], LX),
    LX >= 3,
    length([Y | YS], LY),
    LY is LX + 2,
    append([o, o], [X | XS], W),
    append(W, [o, o], Z),
    cellsR(Z, [Y | YS]).

list_samelength([], []).
list_samelength([_|Xs], [_|Ys]) :-
   list_samelength(Xs, Ys).

See for more on this technique.

false
  • 10,264
  • 13
  • 101
  • 209
  • Thank you for the reply! The solution you suggest seems to do the trick and I suppose it means that this part of the code is now unnecessary `([Y | YS], LY), LY is LX + 2,` since list_samelength already checks that. What I don't understand is why that would happen. – luckysori Apr 11 '16 at 21:13
  • @luckysori: why would **what** happen? – false Apr 11 '16 at 21:35
  • the lack of termination in my original program. I can see where I went wrong, but not why. – luckysori Apr 11 '16 at 21:38
  • 3
    @luckysori: That's what the notion of [tag:failure-slice] is about. Above, I have inserted **`false`** into your program. And the remaining program still did not terminate. It was one of the length goals which described infinitely many different lengths. See the tag for failure-slices to get more examples. If you want to master it, you will have to see many of them. – false Apr 11 '16 at 22:25