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.
Related
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).
twice(X,[X|Y]):-
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]),
X\=Y.
I can't find any syntax error,but the execution fails every time.
You've got a misconception about the list structure. The list [H|T] has head element H and tail list T. So T is itself a list. If you put [T] then that's a list of only one element, that element being the list T.
Also, in your second predicate clause, you don't need the X argument or to check for X \= Y since it's not really relevant if you're checking for at least twice.
Thus, your solution changes a little to:
twice(X, [X|T]) :-
member(X, T).
twice(X, [_|T]) :-
twice(X, T).
Which says that X occurs twice in [X|T] if X is a member of T or X occurs twice in [_|T] if X occurs twice in T.
I like your intent, but cannot reproduce what you claim: that this predicate fails all the time. In fact, it loops! And here is the fragment why failure-slice:
twice(X,[X|Y]):- false,
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]), false,
X\=Y
?- twice(a,[a,a]).
Because this fragment loops, also your original program loops. Lurker has already shown you what is wrong. Here are some alternate formulations:
twice(X, Xs) :-
phrase( ( ..., [X], ..., [X], ... ), Xs).
... --> [] | [_], ... .
Nevertheless, this program has a big flaw:
?- twice(a,[a,a,a]).
true
; true
; true
; false.
Thrice the very same answer. One time is more than enough!
The ambiguity comes from the ...-non-terminal which means just any sequence. There are three ways how that matches the list [a,a,a]:
[ a, a, a ]
...,[X],...,[X], ...
...,[X], ..., [X],...
..., [X],...,[X],...
To remove the ambiguity we need to replace the ... by something more specific. In stead of anything, the sequence should match anything but X. In this way only the first match remains.
twice(X, Xs) :-
phrase( ( all(dif(X)), [X], all(dif(X)), [X], ... ), Xs).
all(_) --> [].
all(P_1) -->
[E],
{call(P_1,E)},
all(P_1).
?- twice(a,[a,a,a]).
true
; false.
That's much better. But is it the bestest? Here is a further improvement using library(reif) for SICStus|SWI.
:- use_module(library(reif)).
twice(C, [X|Xs]) :-
if_(C = X, memberd(X, Xs), twice(C, Xs) ).
memberd(C, [X|Xs]) :-
if_(C = X, true, memberd(C, Xs) ).
?- twice(a,[a,a,a]).
true.
twicee(X,[X|Y]):- member(X,Y).
twicee(X,[_|Y]):-twicee(X,Y), X\=Y.
Working code for me, check if there are two elements in a list. For example:
twicee(X,[a,a,b,b,c,d]).
X = a.
X= b.
twicee(c,[a,a,b,b,d]).
FALSE.
I am trying to write a predicate that given the following list in Prolog:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
will produce the following list:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
As you can see I would like to preserve the order of the elements at the lowest level, to produce elements in the order 1, a, b and NOT b, a, 1.
I would also like to preserve the depth of the lists, that is, lists that are originally nested are returned as such, but in reverse order.
I have managed to achieve the desired order with the following code, but the depth is lost, i.e. lists are no longer nested correctly:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
I would appreciate help in correcting the code to preserve the correct nesting of lists. Thanks!
Two suggestions. First, here's one (rev_lists/2) which uses a bunch of SWI-PROLOG built-ins:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
This one works by testing if all elements of a list L are themselves lists (M); if so, it will recursively apply itself (via maplist) over all individual sub-lists, else it will return the same list. This has the required effect.
Secondly, here's rev_lists/2 again, but written such that it doesn't rely on built-ins except member/2 (which is common):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
It's basically the same strategy, but uses an accumulator to build up reverse lists at each level, iff they are comprised exclusively of lists; otherwise, the same list is returned.
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. :-)
I wanted to write a Prolog program to find equality of two lists, where the order of elements
doesn't matter. So I wrote the following:
del(_, [], []) .
del(X, [X|T], T).
del(X, [H|T], [H|T1]) :-
X \= H,
del(X, T, T1).
member(X, [X|_]).
member(X, [_|T]) :-
member(X, T).
equal([], []).
equal([X], [X]).
equal([H1|T], L2) :-
member(H1, L2),
del(H1, L2, L3),
equal(T, L3).
But when I give input like equal([1,2,3],X)., it doesn't show all possible values of X. Instead, the program hangs in the middle. What could be the reason?
isSubset([],_).
isSubset([H|T],Y):-
member(H,Y),
select(H,Y,Z),
isSubset(T,Z).
equal(X,Y):-
isSubset(X,Y),
isSubset(Y,X).
Try using predicate that checks if one of sets is a permutation of other set:
delete(X, [X|T], T).
delete(X, [H|T], [H|S]):-
delete(X, T, S).
permutation([], []).
permutation([H|T], R):-
permutation(T, X), delete(H, R, X).
(Predicate taken from http://www.dreamincode.net/code/snippet3411.htm)
?- permutation([1,2,3],[3,1,2]).
true
The actual reason for the non-termination that you observed is this: the following clause does not constrain L2 in any way, shape, or form.
equal([H1|T], L2) :-
member(H1, L2),
del(H1, L2, L3),
equal(T, L3).
So your query ?- equal([1,2,3], X). implies proving the goal member(_, L2) which does not terminate universally. Therefore equal([1,2,3], X) cannot terminate universally, too!
For more information on how to explain non-termination of Prolog code read about failure-slice!
PS. Looking at the termination problem from a different angle, we see that the non-termination is, in fact, a necessary consequence in this case.
Why? Because you do not constrain the number of multiplicities, which makes the solution set infinite in size. The set cannot be represented by a finite number of answers (provided you do not permit delaying goals).
If you don't care about the multiplicities of the list elements,
check for sufficient instantiation with
ground/1,
enforce it with
iwhen/2,
and eliminate duplicates with sort/2 like so:
same_elements(As, Bs) :-
iwhen(ground(As+Bs), (sort(As,Es),sort(Bs,Es))).
Sample use with SWI Prolog 8.0.0:
?- same_elements([a,c,c,b,a,c], [c,b,b,a]).
true.
?- same_elements([a,b,b,a], [b,a,b,e]).
false.
?- same_elements([a,b,b,a], Xs).
ERROR: Arguments are not sufficiently instantiated
Try this:
equal([],[]).
equal([Ha|Ta],[Hb|Tb]) :-
Ha = Hb, lequal(Ta,Tb).
How about:
equal(X, Y) :-
subtract(X, Y, []),
subtract(Y, X, []).
So why does equal([1,2,3], X) not terminate universally with your code?
Let's look at a failure-slice of your code! What are failure slices? Here's the tag info:
A failure-slice is a fragment of a Prolog program obtained by adding some goals false. Failure-slices help to localize reasons for universal non-termination of a pure monotonic Prolog program. They also help to give a lower bound for the number of inferences needed. It is a concrete program-slicing technique.
To create a failure slice:
we insert false goals into the program
while making sure that the fragment does not terminate with above goal.
del(_, [], []) :- false.
del(X, [X|T], T) :- false.
del(X, [H|T], [H|T1]) :- false,
dif(X, H), % note that the OP originally used `X \= H`
del(X, T, T1).
member(X, [X|_]).
member(X, [_|T]) :-
member(X, T).
equal([], []) :- false.
equal([X], [X]) :- false.
equal([H1|T], L2) :-
member(H1, L2), false,
del(H1, L2, L3),
equal(T, L3).
?- equal([1,2,3], _), false. % note that `false` is redundant ...
** LOOPS ** % ... as above `equal/2` cannot succeed.
So... what does above failure slice tell us? It says:
To make the goal equal([1,2,3], X) terminate universally ...
... we must change at least one of the remaining parts (the ones not striked-through)!
I suggest using built-in predicate msort/2, then comparing the lists. It takes O(nlogn) time on SWI Prolog, whereas checking unsorted lists naively element-by-element would take O(n2) time.
lists_equal(List1, List2) :-
msort(List1, Sorted1),
msort(List2, Sorted2),
Sorted1=Sorted2.
Here, sorting lists takes O(nlogn) time, and comparing them takes O(n) time on SWI Prolog, I don't know about other implementations.
Briefly
equal([],[]).
equal([H|T],[H|T1]):-equal(T,T1).