how to count odd and even number with using PROLOG - list

question is:
when we key in mem([1,2,3,4,5]).
we will get the output as bellow:
odd=3
even=2
my coding is like that but cannot run. can help me check where is my mistake??
mem(X,[X|L]).
mem(X,[element|L]):-
mem([X,L]).
count([],L,L).
count([X|H],L1,L2):-
write(even),
X%2=0,nl,
write(odd),
X%2>=1,nl,
count([H],[X|L1],L2).
thanks for your helping.

The procedures you have written do two different things and don't actually belong together. mem/2 is equivalent to the usually builtin member/2 except that your definition contains an error: in the second clause element is an atom instead of a variable so it will not match other elements of the list. The usual definition is
member(X, [X|_]).
member(X, [_|L]) :- member(X, L).
Note that this definition will not only test if a term is an element of a list but can even be use to generate a list.
What exactly are you trying to do in count/3: split the list into two lists, one containing odd and the other containing even; or count the number of odd and even elements? The splitting could be done with something like:
count([], [], []).
count([X|L], O, E) :- X rem 2 =/= 0, count(L, [X|O], E).
count([X|L], O, E) :- X rem 2 =:= 0, count(L, O, [X|E]).
Note that =/= /2 and =:= / 2 force evaluation of arguments as arithmetic expressions while = /2 attempts to unify its arguments.
Counting the number of odds and evens can be done in a similar fashion, and is left as an exercise for the reader. :-)

Related

second largest from a list prolog

i'm writing a function that returns true if E is the second largest element from the list, especially trying to use the library https://www.swi-prolog.org/pldoc/man?section=lists
like this:
secLarg([], E).
secLarg([_], E).
secLarg([T], E) :- L is max_member(T, E), delete(T, L), max_member(E, L).
so using some sort of composition of library functions max_member and delete, however this solution is not working, as max_member appears to return only true/false, not what the specific largest element is. do you have any idea about how could I find if E is the second largest element by any way using these functions?
The problem is that L is max_member(T, E) does not make much sense. A predicate does not return a value: it either succeeds or fails. It uses unification to unify a variable with the result.
If you use [T] to unify with, you will only unify with lists with exactly one element. Whereas you probably want to unify with lists with an arbitrary number of elements.
delete/3 also does not alter the list, it produces a new list where it removed the largest member:
secLarg(Xs, E) :-
max_member(Lg, Xs),
delete(Xs, Lg, Xs1),
max_member(E, Xs1).
It also does not make much sense to write secLarg([], E) and secLarg([_], E), since for such lists, there is no second largest:
% secLarg([], E).
% secLarg([_], E).
secLarg(Xs, E) :-
max_member(Lg, Xs),
delete(Xs, Lg, Xs1),
max_member(E, Xs1).
Beware that delete/3 will delete all elements with the given value. Indeed:
?- delete([1,4,2,5,4], 4, R).
R = [1, 2, 5].
So if there is a list where the largest value occurs multiple times, it will not select the largest value (which is also the second largest one).

Remove duplicate from a list but not returning two same results in SWI-Prolog?

duplicate([],[]).
duplicate([A|B],[A|B1]) :- not(member(A,B)), duplicate(B,B1).
duplicate([A|B],List) :- member(A,B), duplicate(B,List).
I wrote this predicate to remove duplicate from the list, but when I test it,
?- duplicate([a,b,c,a,d,c,b,a,e,f],N).
N = [d, c, b, a, e, f] ;
N = [d, c, b, a, e, f] ;
false.
Is there a way to just keep one result only, not two same results? (so it will only return one list).
Also, I am not allowed to use operators that modify the backtracking search, such as the cut operator !, the negation operators not, +, or the if-then-else operator with -> and ;
It would be grateful if someone could help me . :D
The actual reason for receiving more than one answer is the goal member(A,As). It produces multiple answers for duplicates in As.
?- member(a, [a,a]).
true
; true.
There are several ways out.
memberchk/2 or once/1
memberchk/2 is defined as
memberchk(X, Xs) :-
once(member(X, Xs)).
This removes alternate answers. But then, it may remove otherwise valid solutions too. Consider:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
So memberchk/2 is sensitive to the precise instantiation, which makes it a very brittle, impure predicate.
But it has one good point: It sticks to just one answer for
?- memberchk(a, [a,a]).
true.
So what would be ideal is a definition that is both pure and sticking to the first element. Enter
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
In this definition, the recursive rule is only of relevance if the list element is different. Thus this rule will never apply to memberd(a, [a,a,a]).
Another problem in your definition is not(member(A,B)) which only behaves as intended, if A and B are sufficiently instantiated. Your definition fails for:
duplicate([a,X],[a,b]). although there is a solution: X = b.
Rather replace it by non_member/2.
Alternatively, in case you are interested in the most efficient solution, consider library(reif) available
for
SICStus and
SWI which leads to:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Here's one way to remove all duplicates, not the most efficient but I think it's quite easy to understand the intention.
rm_duplicates(In, Out) :-
exclude(has_duplicate(In), In, Out).
has_duplicate(List, Case) :-
dif(I, J),
nth0(I, List, Case),
nth0(J, List, Case).
If you mean to make a list into a set:
list_to_set(List, Set).
It's documented: list_to_set/2

Prolog check if list contains even number of an element

I have to check if a list contains an even number of an element without built-ins.
Example:
containsEvenNumber([a,b,c,a,a], a).
returns false
containsEvenNumber([a,b,c,a], a).
returns true
Current state:
not(A) :-
A, !,
fail.
not(_).
equal([E|_], E).
containsEvenNumber([], _).
containsEvenNumber([E|Tail], E) :-
unevenCount(Tail, E).
containsEvenNumber([Head|Tail], E) :-
not(equal([Head|Tail], E)),
evenCount(Tail, E).
evenCount([], _).
evenCount([E|Tail], E) :-
unevenCount(Tail, E).
evenCount([Head, Tail], E) :-
not(equal([Head|Tail], E)),
unevenCount(Tail, E).
unevenCount([], _) :-
fail.
unevenCount([E, Tail], E) :-
evenCount(Tail, E).
unevenCount([Head, Tail], E) :-
not(equal([Head|Tail], E)),
unevenCount(Tail, E).
I try to switch between states upon the occurrence of the element.
It doesn't work because I never go into the state, where the head is not the element or rather said, I also go into the state and return false when the head is the element.
How can I make it work/fix it?
The "switching between states" is actually a good way to solve this problem. The logic should follow these simple rules:
There are an even number of X elements in [X|Xs] if there are an odd number of X elements in Xs.
There are an even number of X elements in [Y|Xs] if X and Y are different, and there are an even number of X elements in Xs.
There are an odd number of X elements in [X|Xs] if there are an even number of X elements in Xs.
There are an odd number of X elements in [Y|Xs] if X and Y are different, and there are an odd number of X elements in Xs.
Then you have the base cases:
There are an even number of any element in [].
There are an odd number of X in [X].
You just need to write these rules as Prolog. However, your implementation has a few issues.
In a few cases, you are writing a list as [Head, Tail] instead of [Head|Tail]. [Head, Tail] is a list of exactly two elements. Also, your base case for unevenCount/2 (which I assume you mean odd count) is incorrect. If you have a base case that always fails, then your predicate will always fail. With few exceptions, you should write your predicate clauses to succeed, not fail. Failure will occur automatically when success cannot be achieved.
Let's try to write out the rules above. ISO Prologs already have \+, so you do not need to define not/1. Also, writing equal([E|_], E). is unnecessary. You can do this directly in your code with simplicity.
evenCount(_, []). % base case for even
evenCount(X, [X|Xs]) :- % rule #1
oddCount(X, Xs).
evenCount(X, [Y|Xs]) :- % rule #2
dif(X, Y),
evenCount(X, Xs).
oddCount(X, [X]). % base case for odd
oddCount(X, [X|Xs]) :- % rule #3
evenCount(X, Xs).
oddCount(X, [Y|Xs]) :- % rule #4
dif(X, Y),
oddCount(X, Xs).
SWI Prolog defines dif/2. You could also use \== but it's not purely defined (and so doesn't behave as generally) as dif/2.

How to add and compare members in a list

I'm trying to write a predicate is_multi(M), defined as:
every element of M has the form X / N, where X is an atom, and N is an integer greater than 0;
M does not contain two elements with the same atom, for what
is_multi([]).
is_multi([a / 2, b / 2]).
are satisfied, but
is_multi([a, b/2]).
is_multi([a/0, b/2]).
is_multi([a/2, 2/4])
is_multi([a/2, b/3, a/2])
is_multi([a/3, b/-4, c/1])
are not.
Here's what I have written so far:
is_multi(M) :- M = [].
is_multi(M) :-
M = [Head|Tail],
Head = X/N,
integer(N),
N > 0,
is_multi(Tail).
But it does not compare two elements if with the same atom. For example, is_multi([a/2, a/3]) is not satisfied. I got stuck for one day with this; could somebody give me some hints?
First, you can simplify your code considerably by moving some of your unifications from the body to the head.
is_multi([]).
is_multi([X/N|Tail]) :-
integer(N), N > 0,
is_multi(Tail).
Cleaning it up reveals one thing you're not doing here which is in your spec is checking that X is an atom. Fix by adding atom(X) to the body.
OK, so this takes care of the basic form, but doesn't ensure that the atoms do not repeat. The simplest thing to do would be to split this into two checks, one that checks that each item is well-formed, and one that checks that the list is well-formed. In fact, I would be inclined to use maplist/2 with a predicate that checks a single element. But all you really have to do is something like this:
is_valid([]).
is_valid([X/_|T]) :- is_valid(T), \+ memberchk(X/_, T).
This just says that the empty list is valid, and if the tail is valid, a list is valid if X over something doesn't occur in the tail.
If that's all you wanted, stop reading there. If you want to refactor, this is how I would approach it:
well_formed(X/N) :- atom(X), integer(N), N > 0.
no_repeating_numerators([]).
no_repeating_numerators([X/_|T]) :- no_repeating_numerators(T), \+ memberchk(X/_, T).
is_multi(L) :- maplist(well_formed, L), no_repeating_numerators(L).
Just to complete Daniel's instructive answer (+1 by me), I want to showcase how your task could be solved by means of some library predicates:
is_multi(L) :-
forall(select(E, L, R),
(E = A/N, atom(A), integer(N), N > 0, \+memberchk(A/_, R))).

Reverse list of lists

I have a problem with my prolog code. I need to reverse all atomic elements of list.
Example: [1,2,[3,4]] -> [[4,3],2,1]
My solution:
myReverse([], []).
myReverse([H|T], X) :- myReverse(T, RT), myAppend(RT, H, X).
But it only gives me: [[3,4],2,1]
I think, I need to use is_list function and recursive call list if it's not atomic... but I am stuck... do you guys know how to write it?
Nearly. Consider this solution:
myReverse([], []) :- !.
myReverse([H|T], X) :-
!,
myReverse(H, NewH),
myReverse(T, NewT),
append(NewT, [NewH], X).
myReverse(X, X).
The first clause is the base case, which includes a cut (!) to exclude choices left because of the last clause.
The second clause reverses the head H, which may be an atom or a list. If H is an atom, the recursive subgoal after the cut evaluates with the last clause, and atoms are passed through unchanged. If H is a list, it is evaluated with the second clause and all elements are reversed. The next subgoal does the same with the remainder of the list (the tail, T), then are finally concatenated using the built-in append/3. Note that the new head element NewH is singular, so needs to be added to a singleton list structure as [NewH] as per the definition of append/3 which operates on lists.
The last clause passes all other things (i.e., atoms, numbers, etc. - anything that isn't a list or a variable) through unchanged.
revall(L, Y) :-
revall(L, [], Y).
revall([], Y, Y).
revall([H|T], T2, Y) :-
is_list(H),!,
revall(H, Hr),
revall(T, [Hr|T2], Y).
revall([H|T], T2, Y) :-
revall(T, [H|T2], Y).
here without append