0

How can I write a a program in prolog to print even and odd numbers between a range?

Sample output:

Enter first number:2
Enter Second number:15
Even numbers:
2
4
6
8
10
12
14
Odd numbers:
1
3
5
7
9
11
13
15
Guy Coder
  • 24,501
  • 8
  • 71
  • 136

5 Answers5

2

Here's one way to do it:

odds_and_evens( H , H , [H]      , []    ) :- % if lo and hi have converged,
  0 =\= H rem 2                               %   and it's odd
  .                                           %   then park it with the odds and succeed.
odds_and_evens( H , H , []       , [H]   ) :- % if lo and hi have conveged,
  0 =:= H rem 2                               %   and it's even
  .                                           %   then park it with the evens and succeed.
odds_and_evens( L , H,  [L|Odds] , Evens ) :- % else... park lo with the odds
  L < H,                                      % - if lo is less than hi
  0 =\= L rem 2,                              % - and lo is odd 
  L1 is L+1,                                  % - increment lo
  odds_and_evens(L1, H, Odds, Evens )         % - and recurse down
  .                                           %
odds_and_evens( L , H,  Odds , [H|Evens] ) :- % else... park lo with the evens
  L < H,                                      % - if lo is less than hi
  0 =:= L rem 2,                              % - and lo is even
  L1 is L+1,                                  % - incement lo
  odds_and_evens(L1, H, Odds, Evens )         % - and recurse down
  .                                           % Easy!

But... Prolog has an in-built between/3 that generates a range of integers. And findall/3 finds all the solutions to a query as a list. So one could also — and more succinctly and declaratively! — say:

odds_and_evens( L , H , Odds , Evens ) :-
    findall( X , odds(  L , H , X ) , Odds ),
    findall( X , evens( L , H , X ) , Evens )
    .

odds(  L , H , N ) :- between(L,H,N), 0 =\= N rem 2 .

evens( L , H , N ) :- between(L,H,N), 0 =:= N rem 2 .

Once you have odds_and_evens/4 defined, you can than do this:

print_odds_and_evens( Lo, Hi ) :-
  odds_and_evens(Lo,Hi,Odds,Evens),
  write_to_console('Odd Numbers', Odds ),
  write_to_console('Even Numbers', Evens )
  .

write_to_console(Label, Ns ) :-
  write(Label), writeln(':'),
  write_to_console(Ns)
  ,

write_to_console([]) .
write_to_console([N|Ns]) :- writeln(N), write_to_console(Ns).

If that's too much recursion for you, you could also say (cribbing odds/3 and evens/3 from above):

print_odds_and_evens(Lo,Hi) :-
  writeln('Odd Numbers:'),
  odd(Lo,Hi,N),
  writeln(N),
  fail
  .
print_odds_and_evens(Lo,Hi) :-
  writeln('Even Numbers:'),
  even(Lo,Hi,N),
  writeln(N),
  fail
  .
print_odds_and_evens(_,_).

  

odd(  L , H , N ) :- between(L,H,N), 0 =\= N rem 2 .

even( L , H , N ) :- between(L,H,N), 0 =:= N rem 2 .
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • Minor observation: "Prolog has an in-built between/3 ..." It's a de facto standard predicate (i.e. not an ISO Prolog standard predicate) but it's not always available as a built-in predicate but as a library predicate (e.g. in Ciao Prolog, Scryer Prolog, SICStus Prolog, or XSB). – Paulo Moura Aug 06 '21 at 18:27
  • Despite the peculiar formatting and archaic style, you are the only one who used between/3 so you get a point for that. Now you only need to figure out how to use `\+ ( Generator, \+ Side_effect )` as a cleaner failure-driven loop. – TA_intern Aug 11 '21 at 13:13
  • Not sure I'd agree with you that that's a "cleaner" anything. And Prolog is about pattern matching as much as anything else. Alignment helps readers with cognition and pattern recognition. – Nicholas Carey Aug 11 '21 at 18:33
1

There are several possible solutions. Here a, naive, without using higher order predicates:

print_even_odd(Lower,Upper,[],[]):-
    Lower > Upper, !.
print_even_odd(Lower,Upper,Lodd,Leven):-
    Res is Lower mod 2,
    (   Res =:= 0 -> 
            Leven = [Lower | LE1], LO1 = Lodd ;
            Lodd = [Lower | LO1], LE1 = Leven
    ),
    L1 is Lower + 1,
    print_even_odd(L1,Upper,LO1,LE1).

?- print_even_odd(1,15,LE,LO).
LE = [1, 3, 5, 7, 9, 11, 13, 15],
LO = [2, 4, 6, 8, 10, 12, 14]

You can write more compact solutions using higher order predicates as sugggested in the comments.

damianodamiano
  • 2,528
  • 2
  • 13
  • 21
  • 2
    I'd suggest replacing `append([Lower],LE1,Leven)` with the simpler `Leven = [Lower|Le1]`. (And same for the other `append`) – jnmonette Aug 06 '21 at 10:07
  • Absolutely, mine was a very naive solution – damianodamiano Aug 06 '21 at 10:23
  • 1
    @damianodamiano Please edit your answer and apply @jnmonette suggestion. Btw, a linter such as the one in Logtalk would have warned you about this redundant use of the `append/3` predicate. – Paulo Moura Aug 06 '21 at 14:49
  • 1
    Done, but I think keeping the version with `append/3` and then in the comment see that the program can be improved is a bit more instructive, since `append/3` is often over used (as in my first code) – damianodamiano Aug 06 '21 at 14:53
1

Here is an answer based on SWI-Prolog partition/4.

example_1(Odd,Even) :-
    numlist(1,15,List),
    partition(is_even,List,Even,Odd).

is_even(N) :-
    0 is N mod 2.

Example run

?- example_1(Odd,Even).
Odd = [1, 3, 5, 7, 9, 11, 13, 15],
Even = [2, 4, 6, 8, 10, 12, 14].

Here is a variation that puts the support predicate into a Lambda.

example_2(Odd,Even) :-
    numlist(1,15,List),
    partition([N]>>(0 is N mod 2),List,Even,Odd).

Example run

?- example_2(Odd,Even).
Odd = [1, 3, 5, 7, 9, 11, 13, 15],
Even = [2, 4, 6, 8, 10, 12, 14].

For answers to the other part of your multi-part question about entering the starting and ending values I would suggest using read_string/5.

See:
How to get user console input into a Prolog list (Answer)
Prolog: How to read data from console and store into database. (Answer)
Other Answers

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
1

Here is a solution that only uses Prolog ISO standard built-in predicates. It's also a fast solution as it avoid meta-predicates and appending lists:

print_even_odd(Lower, Upper) :-
    even_odd(Lower, Upper, Even, Odd),
    write('Even: '), write(Even), nl,
    write('Odd:  '), write(Odd), nl.

even_odd(Lower, Upper, Even, Odd) :-
    Lower =< Upper,
    (   Lower mod 2 =:= 0 ->
        even_odd_lists(Lower, Upper, Even, Odd)
    ;   even_odd_lists(Lower, Upper, Odd, Even) 
    ).
    
even_odd_lists(Upper, Upper, [Upper], []) :-
    !.
even_odd_lists(N, Upper, [N| Even], Odd) :-
    M is N + 1,
    even_odd_lists(M, Upper, Odd, Even).

Sample calls:

| ?- print_even_odd(1, 24).
Even: [2,4,6,8,10,12,14,16,18,20,22,24]
Odd:  [1,3,5,7,9,11,13,15,17,19,21,23]

yes
| ?- print_even_odd(2, 24).
Even: [2,4,6,8,10,12,14,16,18,20,22,24]
Odd:  [3,5,7,9,11,13,15,17,19,21,23]

yes
| ?- print_even_odd(1, 35).
Even: [2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34]
Odd:  [1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35]

yes
Paulo Moura
  • 18,373
  • 3
  • 23
  • 33
  • I can't believe you posted this seeing as how you created [library(Lambda)](https://www.swi-prolog.org/pldoc/man?section=yall). Now I have to wonder if using that library is right. (Confused) – Guy Coder Aug 06 '21 at 10:59
  • 1
    @GuyCoder You mean `library(yall)`. Nothing wrong in using library predicates, including meta-predicates and lambda expressions. They often result in compact solutions. But they can also be inefficient when compared with solutions that avoid them, even if more verbose. That's the case here. From a learning perspective, all the different solutions presented so far provide an enriching experience. That makes all of them worthy. – Paulo Moura Aug 06 '21 at 11:07
  • `You mean library(yall). ` Yes. Thanks for correcting. – Guy Coder Aug 06 '21 at 11:08
  • 3
    In the spirt of worthiness I gave your answer and the answer by @damianodamiano an upvote. :) – Guy Coder Aug 06 '21 at 11:09
1

Here is another possible solution:

% range(+Start, +Stop, +Step, -List)

range(Start, Stop, Step, List) :-
    (   Start > Stop
    ->  List = []
    ;   List = [Start|Rest],
        Next is Start + Step,
        range(Next, Stop, Step, Rest) ).

% even_odd_lists(+Lower, +Upper, -EList, -OList)

even_odd_lists(Lower, Upper, EList, OList) :-
    FirstEven is Lower + Lower mod 2,
    FirstOdd  is Lower + (Lower-1) mod 2,
    range(FirstEven, Upper, 2, EList),
    range(FirstOdd,  Upper, 2, OList).

Some sample queries are:

?- range(1, 10, 3, R).
R = [1, 4, 7, 10].

?- range(1, 10, 2, R).
R = [1, 3, 5, 7, 9].

?- range(2, 10, 2, R).
R = [2, 4, 6, 8, 10].

?- even_odd_lists(1, 15, LE, LO).
LE = [2, 4, 6, 8, 10, 12, 14],
LO = [1, 3, 5, 7, 9, 11, 13, 15].

?- even_odd_lists(2, 15, LE, LO).
LE = [2, 4, 6, 8, 10, 12, 14],
LO = [3, 5, 7, 9, 11, 13, 15].
slago
  • 5,025
  • 2
  • 10
  • 23