2

Please help me with how to count even numbers in a list in Prolog. I am a beginner, just started learning Prolog yesterday. I know to count the elements in the list is

mylen([H|Lc],N) :- mylen(Lc,M),N is M+1.
mylen([],0).

And I think defining even number maybe helpful in this case, and I guess the code is maybe something like:

even(n):-
  N rem 2 =:= 0.

Can you help me with putting these two parts together, so my code counts even numbers? I know I also need to add a counter, but I have no idea of how to do this in Prolog.

Thank you so very much for you help!

CarmeloS
  • 7,868
  • 8
  • 56
  • 103
perryfanfan
  • 161
  • 3
  • 10
  • `even(N) :- N rem 2 =:= 0.` will be *true* if `N` is even. Try to describe your predicate more clearly first. For example, *An empty list has no even numbers* is `mylen([], 0).` And you could have another rule that says, *A list, `[H|T]`, has `N` even numbers if `H` is even, `T` has `N1` even numbers, and `N` is `N1 + 1`*. Or, *A list, `[H|T]`, has `N` even numbers if `H` is odd, and `T` has `N` even numbers.* – lurker Feb 28 '15 at 19:15
  • Thanks for your help. But I do not know how to use if statement in prolog. – perryfanfan Feb 28 '15 at 20:40
  • It's not an `if` statement, *per se*. When you write a predicate rule such as, `foo(X,Y) :- bar(X), bah(Y).` it means, *`foo(X,Y)` is true **if** `bar(X)` is true **and** `bah(Y)` is true*. Your predicate, `mylen([H|Lc],N) :- mylen(Lc,M),N is M+1.` means, *The length of `[H|Lc]` is `N` **if** the length of `Lc` is `M` **and** `N` is `M+1`*. – lurker Feb 28 '15 at 20:47

2 Answers2

2

Currently, you have two rules:

(1) The number of elements in the empty list is 0

my_len([], 0).

(2) The number of elements in the list [H|Lc] is N if the number of elements in the list Lc is M and N is M+1

my_len([H|Lc], N) :- my_len(Lc, M), N is M+1.

You're already armed with a predicate which is true if a number is even, and false if it is not: N is even if the remainder of N when divided by 2 is 0:

even(N) :- N rem 2 =:= 0.

Now you can piece it together. The number of even elements in an empty list is still zero. So you keep rule (1). Your rule (2) will need to change as it will need to check if the head of the list is even. You can do this with with two rules in Prolog which take care of the two different cases (the list head is even, or the list head is odd):

(2a) The number of even elements in list [H|Lc] is N if H is even, and the number of even elements in list Lc is M, and N is M+1.

(2b) The number of even elements in list [H|Lc] is N if H is not even (or H is odd), and the number of even elements in list Lc is N. [Notice that N doesn't change if H is odd.]

I'll leave the rendering of these two rules into Prolog as an exercise. You can use the Prolog negation functor, \+ to test if a number is not even, by \+ even(N). Or you can define an odd(N) :- N rem 2 =:= 1. predicate to use for that case.

lurker
  • 56,987
  • 9
  • 69
  • 103
2

If your Prolog system offers , you can use the tcount/3 in combination with even_truth/2. Here's how:

?- tcount(even_truth, [1,2,3,5,7,9,10], N_even).
N_even = 2.

Both predicates (tcount/3 and even_truth/2) are monotone and preserve ! This makes them very robust and enables you to always get logically sound answers.

Consider the following more general query:

?- Xs = [_,_,_], tcount(even_truth, Xs, N_even).
Xs = [_A,_B,_C], N_even = 0, _A mod 2 #= 1, _B mod 2 #= 1, _C mod 2 #= 1 ;
Xs = [_A,_B,_C], N_even = 1, _A mod 2 #= 1, _B mod 2 #= 1, _C mod 2 #= 0 ;
Xs = [_A,_B,_C], N_even = 1, _A mod 2 #= 1, _B mod 2 #= 0, _C mod 2 #= 1 ;
Xs = [_A,_B,_C], N_even = 2, _A mod 2 #= 1, _B mod 2 #= 0, _C mod 2 #= 0 ;
Xs = [_A,_B,_C], N_even = 1, _A mod 2 #= 0, _B mod 2 #= 1, _C mod 2 #= 1 ;
Xs = [_A,_B,_C], N_even = 2, _A mod 2 #= 0, _B mod 2 #= 1, _C mod 2 #= 0 ;
Xs = [_A,_B,_C], N_even = 2, _A mod 2 #= 0, _B mod 2 #= 0, _C mod 2 #= 1 ;
Xs = [_A,_B,_C], N_even = 3, _A mod 2 #= 0, _B mod 2 #= 0, _C mod 2 #= 0.
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166