1

So i have this predicate triangular(N) in which N is a number and this predicate return true if a number is a triangular number.

My problem is this for some reason my predicate does an infinite loop instead of just summing the numbers until the N.

Example:

?- triangular(3). 3 true

and it doesnt end.

So basically this is priting the sum of numbers until 3 but its doing something i dont understand.

Program:

triangular(N) :- triangular(N,0).

triangular(N,AC) :- triangular(N,AC,N).

triangular(N,AC,0) :-  write(AC).

triangular(N,AC,CONT) :- NCONT is CONT - 1,
                         NAC is AC + NCONT,
                         triangular(N,NAC,NCONT).
Martim Correia
  • 483
  • 5
  • 16

1 Answers1

0

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.