L Étoile
L Étoile

Reputation: 11

How to write a prolog program to print between a given range?

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

Upvotes: 0

Views: 842

Answers (5)

Nicholas Carey
Nicholas Carey

Reputation: 74197

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 .

Upvotes: 2

slago
slago

Reputation: 5509

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].

Upvotes: 1

damianodamiano
damianodamiano

Reputation: 2662

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.

Upvotes: 1

Paulo Moura
Paulo Moura

Reputation: 18663

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

Upvotes: 1

Guy Coder
Guy Coder

Reputation: 24976

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

Upvotes: 1

Related Questions