Question

I'm writing some Peano arithmetic to better learn Prolog. The following is the code I've come up with, and it seems equivalent of what I've seen elsewhere online:

add(X,z,X).
add(X,s(Y),s(Z)) :- add(X,Y,Z).
mult(_,z,z).
mult(X,s(Y),W) :- mult(X,Y,Z), add(X,Z,W).

However if I try to make a simple query, like the divisor pairs of 0, I run into problems:

| ?- mult(X,Y,z).

Y = z ? ;

X = z
Y = s(z) ? ;

X = z
Y = s(s(z)) ? ;

X = z
Y = s(s(s(z))) ? ;

Fatal Error: global stack overflow (size: 32768 Kb, reached: 32765 Kb, environment variable used: GLOBALSZ)

It really bugs me, as to how can it get all the way to Y = 3, but not to Y = 4?

Was it helpful?

Solution

The stack overflow occurs because, for your query, the predicate add/3 is eventually called with a variable as the middle argument. When you backtrack into it, you get a loop that leads to a stack overflow. Consider the call add(X,Y,Z). The first clause gives you a first solution, add(X,z,X). But, on backtracking, when you use the second clause, you unify your query with add(X,s(Y),s(Z)) and recursively call add(X,Y,Z), back to where you started (remember, the middle argument is not instantiated, so Y in s(Y) will also not be instantiated on the call. You're able to get the first four solutions, as you show above, only thanks to the base cases of both predicates. When usage of those base clause (on backtracking) is exhausted, you get into the loop I just explained above.

Try add the following clause as the first clause of the add/3 predicate:

add(X,Y,Z) :-
    write('Called: '), writeq(add(X,Y,Z)), nl, fail.

Retrying the query you will get (hope you are quick with Control-C):

| ?- mult(X,Y,z).

Y = z ? ;
Called: add(_279,z,z)

X = z
Y = s(z) ? ;
Called: add(_279,z,_307)
Called: add(_279,_279,z)

X = z
Y = s(s(z)) ? ;
Called: add(_279,z,_309)
Called: add(_279,_279,_309)
Called: add(z,z,z)

X = z
Y = s(s(s(z))) ? ;
Called: add(s(_307),_307,_309)
Called: add(s(z),s(s(z)),z)
Called: add(s(s(_311)),_311,_313)
Called: add(s(s(z)),s(s(s(s(z)))),z)
Called: add(s(s(s(_315))),_315,_317)
Called: add(s(s(s(z))),s(s(s(s(s(s(z)))))),z)
Called: add(s(s(s(s(_319)))),_319,_321)
Called: add(s(s(s(s(z)))),s(s(s(s(s(s(s(s(z)))))))),z)
Called: add(s(s(s(s(s(_323))))),_323,_325)
...

Hope this helps.

OTHER TIPS

I know that this is a very old post, but I've just started learning Prolog and find the question fascinating. So here's my two cents.

I've noticed that if you change your rule

mult(X,s(Y),W) :- mult(X,Y,Z), add(X,Z,W).

to a disjunction

mult(X,s(Y),W) :- mult(X,Y,Z); add(X,Z,W).

and run the same query

?- mult(X,Y,z).

You'll get some results, but as you can see the SWI Prolog interpreter doesn't show much detail after a point:

?- mult(X,Y,z).
Y = z ;
Y = s(z) ;
Y = s(s(z)) ;
Y = s(s(s(z))) ;
Y = s(s(s(s(z)))) ;
Y = s(s(s(s(s(z))))) ;
Y = s(s(s(s(s(s(z)))))) ;
Y = s(s(s(s(s(s(s(z))))))) ;
Y = s(s(s(s(s(s(s(s(z)))))))) ;
Y = s(s(s(s(s(s(s(s(s(z))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) .

Doing the same in Gnu Prolog looks much better, to put it gently:

| ?- mult(X,Y,z).

Y = z ? ;

Y = s(z) ? ;

Y = s(s(z)) ? ;

Y = s(s(s(z))) ? ;

Y = s(s(s(s(z)))) ? ;

Y = s(s(s(s(s(z))))) ? ;

Y = s(s(s(s(s(s(z)))))) ? ;

Y = s(s(s(s(s(s(s(z))))))) ? ;

Y = s(s(s(s(s(s(s(s(z)))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(z))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(z)))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(z))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(z))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(z))))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))))))) ? ;   
...

In SWI Prolog (and GNU Prolog) you can call the debugger which illustrates a bit more the excellent theoretical analysis of Paulo Moura, regarding the original problem:

 ?- trace, mult(X,Y,z).

As you will see, it seems to be running for ever, so that would explain the stack overflow. See the result of the trace here, in all its glory. You can trace the infinite loop on your browser as well, by running the above trace.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top