lllllllllllll
lllllllllllll

Reputation: 9140

How to handle this "multiple loop" in Prolog?

So basically I am trying to write a Prolog code, simulating this multiple loops:

int foo()
{
   int i, j, m;
   m = 1;
   i = 0;
   for (; i < 5; i++)
   {
      j = 0;
      for (; j < 5; j++)
         m = i + j + m;
   }

   return m;
}

and my Prolog code is like this:

foo(M02) :-
   M01 is 1,
   I01 is 0,
   loop_entry_1(M01, J01, I01, M02, J02, I02).

loop_entry_1(M01, J01, I01, FinalM, FinalJ, FinalI) :-
   I01 < 5, !,
   J01 is 0,                    %%  I failed here!!
   loop_entry_0(M01, J01, I01, M02, J02, I01),
   I02 is I01 + 1,
   loop_entry_1( M02, J02, I02 , FinalM, FinalJ, FinalI).
loop_entry_1( M01, J01, I01,  M01, J01, I01).

loop_entry_0(M01, J01, I01, FinalM, FinalJ, FinalI) :-
   J01 < 5, !,
   M02 is (I01 + J01) + M01,
   J02 is J01 + 1,
   loop_entry_0(M02, J02, I01 , FinalM, FinalJ, FinalI).
loop_entry_0(M01, J01, I01,  M01, J01, I01). 

So the problem is that, each time when execution exit loop_entry_0, J01 has been assigned to 5, and it will failed at J01 is 0.

But I just can not figure out a way to handle this problem...

Could anyone give me some help?

Upvotes: 4

Views: 97

Answers (1)

false
false

Reputation: 10142

You are trying to simulate states in Prolog. And you have already figured out how this can be done: Essentially, by a sequence of logic variables you can simulate a single (unlogical) variable. Such simulations are often called "differences". The common convention is to name such variables like so: S0, S1, S2, ... S. So the "final" state does not have any number. In this manner you can start a rule without knowing how many intermediate states you will need, say:

p(S0, S) :-
   ...

So every time you assign a new value to a variable, you need a new logic variable, too. But then, you say J01 is 0! Wait, we said: new state means new variable! So you will have to introduce a new intermediary variable here, or simply replace J01 in the next goal by 0.

Another common convention related to differences is to put related arguments immediately after each other.

And then, although this is not so often practiced, you might omit the space between such arguments, such that it is better visible that they belong to each other.

Oh, and I forgot: variables that happened to be constant within a loop do not need to be replicated.

So, with all these conventions, foo/1 would be written (note the different argument order!):

foo(M) :-
   loop_entry_1(1,M, 0,_).

loop_entry_1(M0,M, I0,I) :-
   I0 < 5, !,
   loop_entry_0(M0,M1, 0,_, I0),
   I1 is I0+1,
   loop_entry_1(M1,M, I1,I).
loop_entry_1(M,M, I,I).

loop_entry_0(M0,M, J0,J, I) :-
   J0 < 5, !,
   M1 is I + J0 + M0,
   J1 is J0 + 1,
   loop_entry_0(M1,M, J1,J, I).
loop_entry_0(M,M, J,J, _).

B-but: I realize, that we can remove some of the state variables altogether. In fact:

foo(M) :-
   loop_entry_1(1,M, 0).

loop_entry_1(M0,M, I0) :-
   I0 < 5, !,
   loop_entry_0(M0,M1, 0, I0),
   I1 is I0+1,
   loop_entry_1(M1,M, I1).
loop_entry_1(M,M, _).

loop_entry_0(M0,M, J0, I) :-
   J0 < 5, !,
   M1 is I + J0 + M0,
   J1 is J0 + 1,
   loop_entry_0(M1,M, J1, I).
loop_entry_0(M,M, _, _). 

So this was another trick: If you need a state in a simple tail-only recursive function only, then you can dismiss the second argument! Not how important the spaces between arguments are to distinguish a complex state (M) from the simpler ones!


I really should add: Such 1-to-1 translations might be interesting, but do not give a lot of insight for a specific problem.

Upvotes: 3

Related Questions