1
votes

I just started learning about prolog and i'm thoroughly confused.

Consider the following scenario: I have a knowledge base that contains facts about a person, with the format person(Name,age).

Example:

person(brad,20).
person(lindsey,15).
person(sophie,18).
person(charles,24).

I want to create a rule that would evaluate to true when the sum of the ages exceed 40. Furthermore, if queried, it would output/display the names of the people whose ages adds up to 40. So, i tried this:

addsto40(X,Y,Sum) :- person(X,A), person(Y,B), Sum is A + B, Sum > 9.

When i query the following it return the names of two people whose ages add up to a number larger than 40. (i hit ; to get all the solutions). Example of query:

?- addsto40(X,Y,Sum).

this query returns the follwing:

X = brad,
Y = charles,
Sum = 44 ;
X = sophie,
Y = charles,
Sum = 42 ;
X = charles,
Y = brad,
Sum = 44 ;
X = charles,
Y = sophie,
Sum = 42 ;
X = Y, Y = charles,
Sum = 48.

but, this restricts the output to pairs of two. I wanted it to not have a restriction so, the answer could include for example: brad,lindsey, and sophie.

I tried a number of unsuccessful solutions. I thought about implementing addsto40/3, then adding one person until sum reaches 40. However, it's not working the way i want it to work.

addsto40(X,Y,Sum) :- person(X,A), person(Y,B), Sum is A + B, Sum < 40, addper(P,Sum,Newsum).
addsto40(X,Y,Sum) :- person(X,A), person(Y,B), Sum is A + B, Sum > 40.

addper(Y,Sum,Newsum) :- person(Y,X), Newsum is Sum + X, Newsum < 40, addper(P,Newsum,someSum).
addper(Y,Sum,Newsum) :- person(Y,X), Newsum is Sum + X, Newsum > 40.

Could I be guided into the right direction please? Why is this not working? Does the solution lie in implementing a list somehow? Do you have any tips or tricks for prolog beginners? I appreciate any kind of help. Thank you?

1
Please help me!real_patty

1 Answers

1
votes

You should probably use a list, since you are trying to obtain a list of people whose age sums to greater than 40.

Below is how one might do it similar to your approach, but using a list instead.

addsto40([H|_],Sum,NewSum) :- person(H,A), NewSum is A + Sum, NewSum > 40.
addsto40([H|T],Sum,EndSum) :- person(H,A), NewSum is A + Sum, addsto40(T,NewSum,EndSum).

And then your query would be:

addsto40(X,0,Sum).

However, you will notice that the above will include the same person multiple times and your list can have an infinite number of people in it. To fix this, we add a predicate that checks if a list contains a particular member (call it "contains") and use it to make sure that we do not add the same person twice to our solution. I will also factor out the starting sum (0) and starting list (empty) using a helper predicate. The final code would look like below.

addsto40(X,Sum) :- addsto40help(X,0,[],Sum).

addsto40help([H|_],Sum,Used,NewSum) :- person(H,A), not(contains(H,Used)), NewSum is A + Sum, NewSum > 40.
addsto40help([H|T],Sum,Used,EndSum) :- person(H,A), not(contains(H,Used)), NewSum is A + Sum, addsto40help(T,NewSum,[H|Used],EndSum).

contains(X,[X|_]).
contains(X,[_|T]) :- contains(X,T).

And your query would be:

addsto40(X,Sum).