I need to remove all even numbers in first list and save the rest to second list. My first non-working approach was:
remove_even([],[]).
remove_even([H1|T1],
The fact that you have singleton variable warnings is a clue that something isn't right. Your clause header implies you care about a particular variable, but the clause logic doesn't instantiate it or otherwise use it.
Analyzing the rules (clauses) you provided
remove_even([],[]).
Good rule. An empty list with the even numbers removed is the empty list.
remove_even([H1|T1],[H2|T2]):-
H1 mod 2 =:= 0,
remove_even(T1,_).
This rule says, [H2|T2]
is the list [H1|T1]
with even numbers removed if H1
is even, and if I remove the evens from T1
and discard them. That doesn't sound right. It also doesn't say how you are to obtain H2
. Note: you may not want to split the result list in this clause into head and tail if the logic doesn't dictate.
remove_even([H1|T1],[H2|T2]):-
remove_even(T1,T2).
This rule says that [H2|T2]
is [H1|T1]
with even numbers removed if T2
is T1
with the even numbers removed. That sounds partially correct, but the rule doesn't indicate how to handle H1
and H2
.
UPDATE: in your update, the new second clause:
remove_even([El|T],[T]):- El mod 2 =:= 0.
This is closer. One problem is that T
is already a list, so you don't want [T]
but just T
. Then it becomes:
remove_even([E1|T], T) :- E1 mod 2 =:= 0.
Which says: The list [E1|T]
with even elements removed is the list T
if E1
is even. This is a correct statement but isn't complete logic. It doesn't make any stipulation about T
. What if the list T
has even elements? See @Sergey's answer for a corrected version of this specific clause.
Your updated third clause has some new issues:
remove_even([H1|T1],[H2|T2]):-
remove_even(T1,T1).
There are three singleton variables. The rule says, [H1|T1]
with even elements removed yields [H2|T2]
if T1
is itself with even elements removed (i.e., T1
has no even elements). That doesn't sound logical at all. So you need to rethink that rule. I assume you are intending the case where the head is odd (since clause 2 deals with an even head). In that case, you are just copying the head over to the result list. Your clause heading should then look like:
remove_even([H|T1], [H|T2]) :- % case where head is odd
% put rules here that ensure head is odd, and define how T1 and T2 are related
So you would ultimately have 3 clauses: (1) removing the even elements from an empty list, (2) removing even elements from a list whose head is even, and (3) removing the even elements from a list whose head is odd. That all sounds complete. Just follow the logic.
UPDATE4 Response:
The new 3rd clause eliminates a singleton by introducing some issues:
remove_even([El|T1], NewT):-
El mod 2 =\= 0,
remove_even(T1, [NewT|T1]).
Reading through: [E1|T1]
with even elements removed is NewT
if E1
is odd and [NewT|T1]
is a list with even elements removed from T1
. A BIG problem here is that you are using NewT
(a list) as the head of another list [NewT|T1]
, so it's now a list of lists, which will not match anything. See the prior hint for clause 3 above. In addition, there's no longer a part of the rule that says E1
is part of NewT
. If E1
is odd, it should be part of the the other list when even elements are removed.
UPDATE5 Response (why does it now work?):
So the final working version looks like this:
remove_even([],[]).
As before: if you remove the even elements of an empty list, you get an empty list.
remove_even([El|T], NewT):-
El mod 2 =:= 0,
remove_even(T, NewT).
NewT
is the list [E1|T]
with even elements removed if E1
is even and NewT
is T
(the "tail list" of the original list) with the even elements removed from T
. In other words, we dropped E1
(an even element, head of the first list - we don't want it any more since it's even) and are left with T
, the rest of the list which we want to "process" and find the list that's like T
but with the even elements removed.
remove_even([H|T1], [H|T2]):-
H mod 2 =\= 0,
remove_even(T1, T2).
We've covered this one before, but for completeness: [H|T1]
with even elements removed is [H|T2]
if H
is not even and T1
with its even elements removed is T2
. Your description of this clause reads, [H|T2] is a list with even elements removed from [H|T1] IFF Heads of both Lists is odd AND Tail T2 of destination list is a Tail T1 with all even elements removed. This isn't quite accurate. You're saying, "...IFF heads of both lists is odd...", whereas in the clause, we are saying the heads are identical and odd (it's the same number), not just both odd.
All of the cases are covered as I described further before in my answer. If you think about it logically, it makes sense. :)