theiwarlock
theiwarlock

Reputation: 89

Learning prolog, some list functions

I am working on an assignment that deals with lists in prolog. The basic idea is that given a list, prolog should be able to determine if a value is repeated at all, repeated only once, or repeated only twice, etc. I thought the simplest solution would be to count the number of times a value occurs and then use that count to determine how many times it is repeated.

list_count([],X,0).
list_count([X|T],X,Y) :- list_count(T,X,Z), Y is 1 + Z.
list_count([X1|T],X,Z) :- X1 \= X, list_count(T,X,Z).

repeated_in(+E,+List) :- list_count(List,E,Num), Num >= 2.

No matter what I do though my first predicate always fails. Help?

Upvotes: 3

Views: 385

Answers (2)

repeat
repeat

Reputation: 18726

Here a logically pure implementation, based on if_/3 and (=)/3 by @false.

atLeastOnceMember_of(E,[X|Xs]) :-
   if_(E = X, true, atLeastOnceMember_of(E,Xs)).

atLeastTwiceMember_of(E,[X|Xs]) :-
   if_(E = X, atLeastOnceMember_of(E,Xs), atLeastTwiceMember_of(E,Xs)).

First, let's look at the queries you suggested in your question:

?- atLeastTwiceMember_of(a,[a,b,a,b,a,c]).
true.                                       % succeeds deterministically
?- atLeastTwiceMember_of(b,[a,b,a,b,a,c]).
true.                                       % succeeds deterministically
?- atLeastTwiceMember_of(c,[a,b,a,b,a,c]).
false.
?- atLeastTwiceMember_of(x,[a,b,a,b,a,c]).
false.

The code is monotone, so we get logically sound answers for more general uses, too!

?- atLeastTwiceMember_of(X,[a,b,a,b,a,c]).
X = a ;
X = b ;
false.

At last, let us consider a generalization of above query:

?- atLeastTwiceMember_of(X,[A,B,C,D,E,F]).
X = A, A = B                                         ;
X = A, A = C, dif(C,B)                               ;
X = A, A = D, dif(D,C), dif(D,B)                     ;
X = A, A = E, dif(E,D), dif(E,C), dif(E,B)           ;
X = A, A = F, dif(F,E), dif(F,D), dif(F,C), dif(F,B) ;
X = B, B = C, dif(C,A)                               ;
X = B, B = D, dif(D,C), dif(D,A)                     ;
X = B, B = E, dif(E,D), dif(E,C), dif(E,A)           ;
X = B, B = F, dif(F,E), dif(F,D), dif(F,C), dif(F,A) ;
X = C, C = D, dif(D,B), dif(D,A)                     ;
X = C, C = E, dif(E,D), dif(E,B), dif(E,A)           ;
X = C, C = F, dif(F,E), dif(F,D), dif(F,B), dif(F,A) ;
X = D, D = E, dif(E,C), dif(E,B), dif(E,A)           ; 
X = D, D = F, dif(F,E), dif(F,C), dif(F,B), dif(F,A) ;
X = E, E = F, dif(F,D), dif(F,C), dif(F,B), dif(F,A) ;
false.

Upvotes: 2

CapelliC
CapelliC

Reputation: 60014

list_count/3 does work. I think the only issue is the improper usage of prefix '+': try

% repeated_in(+E,+List)
repeated_in(E,List):- list_count(List,E,Num), Num >= 2.

note: prefixing arguments is used for documentation purpose, as a recap about mode usage

Upvotes: 3

Related Questions