Q:

How to check for exactly two elements in a Prolog list

% The structure of a musical group takes the form
% group(Groupname, Director, Players).
% Players is a (possibly empty) list of musician structures,
% but excludes the musician structure for the Director.
% The Director is also a musician in the group.
% musician structures take the form
% musician(Initials,Surname,
% cv(Years_as_professional,Previous_orchestra,Instrument)).

group(classicalstars,
      musician(w,mozart,cv(10,vienna_phil,piano)),
      [musician(j,haydn,cv(32,vienna_phil,cello)), musician(j,bach,cv(40,dresden_chamber,viola))]).
group(romantics,
      musician(l,beethoven,cv(32,vienna_phil,piano)),
      [musician(f,liszt,cv(10,vienna_phil,violin))]).
group(nordicsounds,
      musician(e,grieg,cv(50,bergen_phil,piano)),
      [ ]).
group(impressions,
      musician(g,faure,cv(40,paris_chamber,violin)),
      [musician(c,saint-saens,cv(51,paris_chamber,violin)), musician(m,ravel,cv(10,paris_chamber,piano)), musician(o,messiaen,cv(5,paris_chamber,violin))]).

director(X):- group(_,X,_).

musicians(X):- group(_,_,Musicians),
              member(X,Musicians).

exists(X):- director(X);
            musicians(X).

So I am trying to return the Initial and Surname of the director of the group that has exactly two non-director musicians that play the violin.
So far I have this
 hasTwoViolinists(Initial,Surname):- group(_,musician(Initial,Surname,_),[musician(_,_,cv(_,_,violin)),musician(_,_,cv(_,_,violin))]).  

Which will only return a group that only has two violinists, which isn't quite what I am looking for
Any help would be appreciated

A:

The first thing I did was to understand the structure of your data and noticed that finding a list of musicians that had exactly two violinist would be the inner most rule so I started on that.
Here is a rule to find exactly two items in a list. It needs to be enhanced to work on the musicians list for the violinist.
find(C,_,C,[]).  % True when Count exactly equals Total and list is empty.

% When the head of the list is the item increment the count and do the next item.
find(Total,Item,Count,[H|T]) :-
      Item = H,
      Count1 is Count + 1,
      find(Total,Item,Count1,T).

% When the head of the list is not the item do the next item.
find(Total,Item,Count,[H|T]) :-
      Item \= H,
      find(Total,Item,Count,T).

% find(2,a,0,[a,b,a,c]).
% true .
%
% find(2,a,0,[a,a,a,c]).
% false.

Note: The hints are spoilers and can be seen by moving your mouse over them.
If the hint has a code solution it is below all of the hints and also as a spoiler so you have to move the mouse to see them.
Hint 1:

 Predicates are your friend with Logic Programming.

Hint 2:

 Create a Predicate that returns true when a musician is a violinist, and false when a musician is not a violinist.

 is_violinist(musician(o, messiaen, cv(5, paris_chamber, violin))).
 true.

 is_violinist(musician(m, ravel, cv(10, paris_chamber, piano))).
 false.

Hint 3: 

 find used two predicates.

 Item = H  and
 Item \= H

 what happens when they are replaced with is_violinist

 For reference:
=
\=
\+ is the same as not.  

Hint 4:

 Now that you can find the musicians with the two violinist how can you use that to find the group?

Hint 5:

 Now that you can find the group with the two violinist how can you use that to find the directors initial and surname?

Code for hints. Sorry about the formatting, limits of markdown.
2.

 is_violinist(musician(_,_,cv(_,_,violin))).

3.

 % True when Count exactly equals Total and list is empty.
 find_v(C,C,[]).

 % When is_violinist is true for the head of the list increment the count and do the next item.
 find_v(Total,Count,[H|T]) :-
       is_violinist(H),
       Count1 is Count + 1,
       find_v(Total,Count1,T).

 % When is_violinist is not true for the head of the list do the next item.
 find_v(Total,Count,[H|T]) :-
       \+ is_violinist(H),
       find_v(Total,Count,T).  

4.

 find_group(Group) :-
       group(Group,_,Musicians),
       find_v(2,0,Musicians).  

5.

 find_director(Initial,Surname) :-
       group(_,musician(Initial,Surname,_),Musicians),
       find_v(2,0,Musicians).  

