Jim
Jim

Reputation: 482

Accessing list elements in a list of lists in prolog to operate on

I've been trying to work this out for a good hour now, and am not having any luck.

If I have a list of lists like so

[[tom, dick, harry], [janice, jane, jess]]

And they have the relations

happy(tom).
happy(dick).
happy(harry).
happy(janice).
unhappy(jane).
unhappy(jess).

I want to query each list individually and find out if they are unhappy or happy. Currently I have written two functions to handle this, they are

%% Female happiness checker
hcf([]).
hcf([H|T]) :-
   happy(H),
   hcf(T).

%% Male happiness checker
hcm([]).
hcm([H|T]) :-
   happy(H),
   hcM(T).

So currently individually these do work. If I put in

hcm([Janice, jess, jane]).
false

It returns false, as two people are unhappy.

What I am having trouble with is writing a function which allows me to pass each list from the list of lists into respective functions for each male and female happiness.

So Far I have tried something along the lines of

%% I  was trying to get a HEAD list and a TAIL list to pass them through but didn't have much luck
happnieschecker([[]])
happnieschecker([[H|T]]) :-
some code here

EDIT : I want the program to run like so

happinesschecker([tom, dick, harry], [janice, jane, jess]).
false - since jane and jess are unhappy
happinesschecker([tom, dick, harry], [janice]).
true - since everyone is happy

So my question is, how can I pass every second list into HCF for females and every other list into HCM for males?

Upvotes: 1

Views: 2787

Answers (2)

Nicholas Carey
Nicholas Carey

Reputation: 74177

A prolog list ([a,b,c]) is syntactic sugar for the data structure ./2, with the empty list denoted by the atom [].

  • the list [a] is exactly identical to .(a,[])
  • the list [a,b] is exactly identical to .(a,.(b,[]))
  • the list [a,b,c] is exactly identical to .(a,.(b,.(c,[])))

Myself, I'd rather use the square bracket notation. You?

Prolog's list notation offers more syntactic sugar, using the | operator to partition the list into a head and a tail.

  • The notation [a|X] is exactly identical to `.(a,X)
  • the notation [a,b|X] is exactly identical to .(a,.(b,X))
  • the notation [a,b,c|X] is exactly identical to .(a,.(b,.(c,X)))

Given that, and assuming your list-of-lists contains alternating sublists of males and females:

[ [bob,ted] , [carol,alice] , [tom,dick,harry] , [jane,sally,simone] ]

something like this should work for you

everybody_happy( []         ) .                 % the empty list is all happy
everybody_happy( [Ms]       ) :-                % a list of length 1 contains a male sublist
  findall( M , (member(M,Ms),happy(M)) , Ms )   % is everybody happy?
  .                                             %
everybody_happy( [Ms,Fs|Ps] ) :-                % a list of length 2+ starts with a male and female sublist
  findall( M , (member(M,Ms),happy(M)) , Ms ) , % are all the boys happy?
  findall( F , (member(F,Fs),happy(F)) , Fs ) , % are all the girls happy?
  everybody_happy(Ps)                           % is the remainder of the list happy?
  .                                             % easy!

I'm using findall/3 here. If you want to roll your own happiness checker, just replace findall/3 with your implementation:

everybody_happy( []         ) .  % the empty list is all happy
everybody_happy( [Ms]       ) :- % a list of length 1 contains a male sublist
  is_happy(Ms)                   % is everybody happy?
  .                              %
everybody_happy( [Ms,Fs|Ps] ) :- % a list of length 2+ starts with a male and female sublist
  is_happy( Ms ) ,               % are all the boys happy?
  is_happy( Fs ) ,               % are all the girls happy?
  everybody_happy(Ps)            % is the remainder of the list happy?
  .                              % easy!

is_happy([]).        % the empty list is happy
is_happy([P|Ps] ) :- % a non-empty list is happy IF... 
  happy(P) ,         % - its head is happy, and
  is_happy(Ps)       % - its tail is happy
  .                  % easy!

Edited to note: if you want to discard the first item, try something like

everybody_happy( [_|Xs] ) :-
  every_body_happy_1( Xs )
  .

where everybody_happy_1/1 is the actual predicate.

Upvotes: 1

false
false

Reputation: 10102

happynesschecker(Ms, Fs) :-
   allhappy(Ms), % more compactly:  maplist(happy,Ms).
   allhappy(Fs). 

allhappy([]).
allhappy([P|Ps]) :-
   happy(P),
   allhappy(Ps).

Note that the very same predicate can be used for both the males and females list.

And for a list of list of persons:

extrahappy(Mss) :-
   maplist(maplist(happy), Mss).

or more verbosely:

extrahappy([]).
extrahappy([Ps|Pss]) :-
   allhappy(Ps),
   extrahappy(Pss).

Upvotes: 2

Related Questions