1
votes

I've started a Prolog course and I've been given the following word problem as homework. I'm fine with understanding arithmetic problems, but I'm struggling to get this word problem right. I've pasted my solution, but it only succeeds for the first test and not the second test. Could you please help me to understand what I'm doing wrong? In the textbook, problems with "every person" often use the _ to indicate it could be anyone, so I'm wondering if that is what I'm missing? Or is my logic just wrong? Thanks!

Write a predicate eats_all(Person, Food) that takes a list of people Person and a list of items Food and succeeds if every person in Person eats every item in Food, according to the predicate eats(Name, Item). It will succeed if either Person or Food is empty. Test cases:

?- eats_all([john,tony],[pizza,burgers]).
true
?- eats_all([],[tacos]).
true

Facts:

eats(melissa, pizza).
eats(melissa, pies).
eats(melissa, hotdogs).
eats(tony, burgers).
eats(tony, pizza).
eats(john, pizza).
eats(john, burgers).

My solution so far:

% the first person in Person list eats all foods in Food list (sub-problem);
first_person(_, []).
first_person(X, [Head_Food|Tail_Food]) :-
    eats(X, Head_Food),
    first_person(X, Tail_Food).

% main problem
eats_all([], _).            
eats_all([Head_Person|Tail_Person], [Head_Food|Tail_Food]):-   
    eats(Head_Person, Head_Food),  
    eats_all(Tail_Person, Tail_Food). 
1

1 Answers

1
votes

You almost get there. For you are new to prolog, it's good to break the problem into subproblems. First, lets think recursively:

- Base case: eats_all(_, []). and eats_all([], _).
- Recursive case: 
      + the first person in Person list eats all foods in Food (here is a subproblem); 
      + recursive call of the function eats_all for the rest of Person list.

% sub-problem: succeed if a person X eats all foods in Food
eat_all_food(_, []).
eat_all_food(X, [F|Fs]) :-
eats(X, F),
eat_all_food(X, Fs).

% main problem: succeed if all persons in Person eat all foods in Food
eats_all([], _).
eats_all(_, []).
eats_all([X|Xs], Y) :-
   eat_all_food(X, Y),
   eats_all(Xs, Y).

One more thing: using _ only means that you don't care what the value of parameter is (as seen in the base case, when Food is an empty list, the function always returns true regardless of Person).

Have fun.