Background infomation
Prolog can search for more than one solution to your query.
Consider this program:
human(alice).
human(bob).
When you query ?- human(X).
, Prolog will search for assignments for X
that match your program. It will show you the solution X = alice
. Afterwards you can either stop searching by pressing .
or continue searching by pressing ;
. If you continue, Prolog will then find X = bob
. Afterwards it will stop because it has exhausted all possible solutions:
?- human(X).
X = alice .
?- human(X).
X = alice ;
X = bob.
You can control the search process using the cut predicate !
. The cut predicate cuts off alternative paths in the current layer. So if you extend the above program with this rule:
find_first_human(X) :- human(X), !.
Running the query ?- find_first_human(X).
will only only output X = alice.
, without searching for further answers. Prolog knows that the human(X)
can be resolved in multiple ways, but then the !
tells Prolog to ignore those alternatives.
Applying this to your program
The main problem is that your last triangle
predicate does not require CONT > 0
. So when you query ?- triangle(3).
, Prolog eventually arrives at triangular(3,3,0).
, which matches your write
rule. As you can see, your program outputs 3
as expected. However, Prolog then sees that there are alternatives solutions for triangular(3,3,0)
, so it offers you to continue searching. You can stop by pressing .
, or continue by pressing ;
. If you continue, Prolog will try the last rule for triangular
, with CONT
being resolved to 0
. Thus NCONT
becomes -1
. This will then go into an infinite loop, where the last triangular
rule is applied repeatedly, decrementing CONT
with no end.
You can verify this by using trace.
(can be disabled again with notrace.
):
?- trace.
?- triangular(3).
Call: (8) triangular(3) ? creep
Call: (9) triangular(3, 0) ? creep
Call: (10) triangular(3, 0, 3) ? creep
...
Call: (13) triangular(3, 3, 0) ? creep
Call: (14) write(3) ? creep
3
Exit: (14) write(3) ? creep
Exit: (13) triangular(3, 3, 0) ? creep
...
true ;
Redo: (13) triangular(3, 3, 0) ? creep
Call: (14) _2076 is 0+ -1 ? creep
Exit: (14) -1 is 0+ -1 ? creep
...
You can stop this by changing the last rule to:
triangular(N,AC,CONT) :- CONT > 0,
NCONT is CONT - 1,
NAC is AC + NCONT,
triangular(N,NAC,NCONT).
This forbids Prolog from applying the rule for triangular(3,3,0)
. When you run the query ?- triangular(3).
with the modified program, Prolog should then write out the 3
as before when arriving at triangular(3,3,0)
. Afterwards it detects that there could be alternative solutions. If you press ;
, it then detects that the last rule cannot be applied because the CONT > 0
constraint does not hold. It then stops searching:
?- triangular(3).
3
true ;
false.
We can further simplify this with the cut predicate !
shown in the previous section, by modifying the write
rule to:
triangular(N,AC,0) :- write(AC), !.
This tells Prolog to not search for alternative solutions to triangular(3,3,0)
. When you run the query ?- triangular(3).
, Prolog should then write out the 3
as before, and then exit without further search:
?- triangular(3).
3
true.