1
votes

I am using the below family database to practice prolog. I want to...

'Find the first name and surname of mothers whose children’s combined incomes are greater than £140,000, where at least one child is unemployed. The rule should also return the first name of the unemployed child/children, and the value of the children’s combined incomes'

so far I have this code...Help would be appreciated, really struggling on this exercise. thanks :)

(Fname,Sname,Income):- 
family(person(_,_,_,_),person(Fname,Sname,_,_),Children),
total(Children,Income),
Income > 140000.

.

total([Person|List],Sum):-
salary(Person,S),   % S: salary of the first person
total(List,Rest),   % Rest: sum of salaries of others
Sum is S + Rest.

.

family(
person(pat,marx,date(10,march,1944),unemployed),
person(charlotte,marx,date(11,february,1946),unemployed),
[
    person(aine,marx,date(17,april,1985),unemployed),
    person(louis,marx,date(25,june,1980),works(harriott,32000)),
    person(pearl,marx,date(10,june,1981),unemployed),
    person(pat_jr,marx,date(11,march,1983),works(world_of_food,850000)),
    person(ricky,marx,date(18,february,1987),unemployed)
]
).

family(
person(fred,chomsky,date(3,october,1955),works(bean_counters,100000)),
person(sarah,chomsky,date(19,october,1961),works(supercomms, 60000)),
[   
person(amos,chomsky,date(1,july,1984),works(sell_cell, 80000))
]
).

family(
person(ted,marx,date(10,july,1948),unemployed),
person(adelheid,marx,date(9,december,1948),unemployed),
[   person(ted_jr,marx,date(14,april,1988),works(world_of_food,90000)),
    person(jenny,marx,date(23,may,1984),unemployed),
    person(margaret,marx,date(23,may,1984),unemployed),
    person(sadie,marx,date(23,may,1984),unemployed),
    person(louis,marx,date(22,august,1979),unemployed),
    person(alan,marx,date(9,may,1990),unemployed)
]

).

family(
person(ted,russell,date(21,may,1938),retired),
person(victoria,russell,date(9,november,1944),retired),
[   person(betty,russell,date(18,august,1971),works(boat_house,65000)),
    person(jack,russell,date(27,may,1965),works(green_machine,15000)),
    person(joan,russell,date(9,april,1963),works(green_machine,15000)),
    person(penelope,russell,date(9,april,1963),works(green_machine,15000)),
    person(enda,russell,date(2,november,1968),works(exc-u-vate,15000)),
    person(amos,russell,date(27,may,1965),works(green_machine,15000)),
    person(algernon,russell,date(2,november,1968),works(exc-u-vate,15000)),
    person(cal,russell,date(9,october,1970),works(sell_cell,30000))
]

).

family(
person(bill,kant,date(7,august,1942),works(fibrefast,100000)),
person(ann,kant,date(9,october,1945),works(roulada,100000)),
[   person(mark,kant,date(25,april,1970),works(harriott,36000)),
    person(cal,kant,date(22,december,1966),works(harriott,35000)),
    person(simon,kant,date(27,january,1965),works(harriott,31000)),
    person(sol,kant,date(17,november,1964),unemployed),
    person(andrew,kant,date(9,march,1968),works(harriott,32000)),
    person(joan,kant,date(27,january,1965),works(harriott,34000))
]

).

family(
person(ted,russell,date(6,june,1950),works(mopper-ups,25000)),
person(helen,russell,date(10,june,1951),works(harriott,110000)),
[   person(maura,russell,date(21,february,1972),works(sparrow_hotel,19000)),
    person(simon,russell,date(24,december,1970),works(zoom-away,50000)),
    person(victoria,russell,date(23,january,1971),works(volts,49000)),
    person(andrew,russell,date(24,june,1969),works(sparrow_hotel,35000)),
    person(cal,russell,date(15,april,1974),works(sparrow_hotel,55000)),
    person(milly,russell,date(21,february,1972),works(sparrow_hotel,19000))
]

).

1

1 Answers

0
votes

This is a very odd database layout, but that doesn't need to stop us. First the head of the rule with the things we're going to return:

q(MotherFirst, MotherLast, UnemployedKids, CombinedIncome) :-

We're considering families here, so let's match them and pull out the mother's info:

    family(_, person(MotherFirst, MotherLast, _, _), Children),

The underscores there correspond to the father, the mother's date-of-birth and occupation. None of those are relevant to the problem so forget 'em. Next we need to do some processing on the kids: we need to find the ones that are unemployed and get the combined income. I will do two traversals because it's simpler for me. First the sum of their income:

    total_income(Children, CombinedIncome),
    CombinedIncome > 140000,
    unemployed(Children, UnemployedKids),
    UnemployedKids = [_|_]. % ensure we have at least one unemployed kid

I've broken the task down a little bit; let's go ahead and write some helpers:

% compute the total income for a list of people
total_income([], 0).
total_income([person(_, _, _, works(_, Amount) | People], Total) :- 
    total_income(People, Subtotal),
    Total is Subtotal + Amount.

% find the unemployed people in a list of people
unemployed([], []).
unemployed([person(FN, LN, DOB, unemployed) | People], 
           [FN | Unemployed]) :-
    !, % cut so that we don't enter the next rule with someone who is unemployed
    unemployed(People, Unemployed).
unemployed([_|People], Unemployed) :- unemployed(People, Unemployed).

Both of those could be simplified considerably using library(aggregate) or even some folds (perhaps with library(lambda) but this is a straightforward "classic" (wordy) solution.