1
votes

I am trying to count from 0 to N, one value returned at a time, rather than a list like with numlist/3. I believe it is possible to use recursion with two predicate statements, but I have gotten caught up on coming up with a stop condition which works in the manner I am looking for:

iterate(0,_).
iterate(X,N) :- iterate(Y,N), Y < N, X is Y + 1.

With my current understanding, the first predicate will always return 0 as the first value when calling iterate(X,N), and the second will iterate through recursive calls giving the next value.

The issue I have run into is that it correctly counts up to N, but then reaches the stack limit. I think that this is due to making the recursive call at the beginning of the predicate and checking on the return result afterwards.

The main disconnect seems to be my understanding of how Prolog deals with predicates. From what I have read, it seemed that Prolog handles the second call as follows:

iterate(Y,N) ⋀ (Y < N) ⋀ (X is Y + 1)

I thought that this would mean that when Y < N returns false, the recursive call would stop, which is not the case. At this point, I have tried a couple variations of the recursive call location in the predicate, always with the final value of X being declared at the end as it seems like that's where the value declaration must go.

I have also seen that ISO-Prolog has (;)/2 (if-then-else), but have not found anything similar which may be helpful in SWI-Prolog that could apply to this case.

Am I wrong in thinking that this is possible to do this with two predicate statements in SWI-Prolog?

Edit: I intend on doing this without an accumulator for added challenge.

5
What is the problem with using an accumulator?Willem Van Onsem
Note that the ; is not the if-then-else but the "OR". The "if-then-else" is the ->David Tonhofer
Correct. In SWI-Prolog ; is "OR", but in ISO-Prolog it is the "if-then-else" statement. Thank you for directing me to the -> operator in SWI, it helped me solve my problem!TheWubMunzta

5 Answers

1
votes

I thought that this would mean that when Y < N returns false, the recursive call would stop, which is not the case.

Prolog evaluates left-to-right (or well top to bottom), so it will first make a recursive call, and when that call is successful, then it will check the next part Y < N, so using it that way, it will indeed get stuck in an infinite loop, since it will keep making more recursive calls that all eventually will fail the Y < N test, but nothing stops Prolog from making a new recursive call.

You can thus swap the order to:

iterate(I, J, I) :-
    I =< J.
iterate(I, J, R) :-
    I < J,
    I1 is I + 1,
    iterate(I1, J, R).

This then gives us:

?- iterate(10, 15, R).
R = 10 ;
R = 11 ;
R = 12 ;
R = 13 ;
R = 14 ;
R = 15 ;
false.

It thus means that in a range [I .. J], I is a member of that range (firs clause), and if I < J, then the elements of [I+1 .. J] are also members of that range (second clause).

0
votes

Here is my approach:-

printSeries(_,0):-!.
printSeries(S,C):-
    S1 is S+1,
    C1 is C-1,
    writeln(S),
    printSeries(S1,C1). 

?-printSeries(1,10).
1
2
3
4
5
6
7
8
9
10
1true

?-printSeries(15,10).
15
16
17
18
19
20
21
22
23
24
1true

?-printSeries(0,10).
0
1
2
3
4
5
6
7
8
9
1true



?-printSeries(0,5).
0
1
2
3
4
1true
0
votes

That's a lot of questions in one.

Let's start with a program:

So you want to count up from 0 to to maximum, here given by N.

one value returned at a time

It is difficult to judge what that means as Prolog predicates do not "return values" - they just succeed or fail (or throw an exception) while possibly binding variables to values for the next predicate to use after the ,.

But let's suppose we just want to print the sequence of numbers. Then:

print_them(Max) :-               % Predicate to "count up to Max"
   pth2(Max,0).                  % It calls a a helper predicate that counts ...
                                 % ... up to "Max" starting at 0

% ---
% pth2(+Max,+C)                  % Predicate: "Count to Max starting at C"
% ---

pth2(Max,Max) :-                     % We will stop with Max == C
   format("I'm at max: ~d\n",[Max]). % Just print something in that case.

pth2(Max,C) :-                       % Case of Max not necessarily being C
   C < Max,                          % "guard": only proceed "rightwards" if C < Max
   format("I'm at ~d\n",[C]),        % and then some printing
   Cp is C + 1,                      % Evaluation: C is known, so compute a Cp
   pth2(Max,Cp).                     % ...and then count to Max from Cp.

pth2(Max,C) :-                       % Case of Max not necessarily being C, again
   C > Max,                          % "guard": only proceed "rightwards" if C > Max
   throw("C exceeds Max").           % And then throw an exception

Is the above clearer?

And so:

?- print_them(12).
I'm at 0
I'm at 1
I'm at 2
I'm at 3
I'm at 4
I'm at 5
I'm at 6
I'm at 7
I'm at 8
I'm at 9
I'm at 10
I'm at 11
I'm at max: 12
true ;              <--- success but maybe there are other solutions?
false.              <--- nah, actually not
0
votes

What you really seem to need is between/3. Like this:

?- between(0, 4, X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4.

?- forall(between(0, 4, X), format("~w~n", [X])).
0
1
2
3
4
true.

between/3 is a built-in. It is relatively difficult to program is yourself and cover all edge-cases.

Note that you can also filter the results, for example only odd numbers:

?- between(0, 9, X), X rem 2 =:= 1.
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9.

Or naively print out only primes:

?- between(1, 9, X), succ(X0, X), forall(between(2, X0, Y), X rem Y =\= 0).
X = 1 ;
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
false.
0
votes

I ended up figuring out a way to count from 0 to n without an accumulator by tweaking my initial code snippet. While David Tonhofer solved the problem stated, I would like to post my solution that solves my added challenge goal.

iterate(0,_).
iterate(X,N) :- iterate(Y,N), (Y < N -> X is Y + 1; !).

This snipped of code allows iterate(X,N) to be called, with N being a real number and X a variable, and have X iterate through every value from 0 to N inclusively. This allows for testing every integer value from 0 to N against equations and find solutions.

It will return the values below when iterate(X,N) is called:

?- iterate(X,10).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = 6 ;
X = 7 ;
X = 8 ;
X = 9 ;
X = 10 ;
true.