Checking a relation of a prolog list element

2019-07-07 04:51发布

问题:

Lets say I have a relations

Happy(james)
Happy(harry)
unhappy(Tom)
unhappy(Ben)
unhappy(Dick)

And then a list of people

[Ben, James, Harry, Tom, Dick]

How can I iterate the list and check the boolean of each list element as to whether they are happy or not?

回答1:

Well, first of all, in Prolog, if a word starts with a capital letter, it means that it is a variable. So you should be careful with that.

This is my database after the correction:

happy(james).
happy(harry).
unhappy(tom).
unhappy(ben).
unhappy(dick).

and I added a recursive rule that helps me see who is happy and who is not from a given list:

emotion([]).
emotion([H|T]):- happy(H),emotion(T),
                 write(H),write(' is happy.'),
                 nl;
                 unhappy(H),emotion(T),
                 write(H),write(' is unhappy.'),
                 nl.

Here is the result:

4 ?- emotion([ben, james, harry, tom, dick]).
dick is unhappy.
tom is unhappy.
harry is happy.
james is happy.
ben is unhappy.
true.


回答2:

Here is another approach to dealing with this task. This answer doesn't fuss with with IO, which is unnecessary here, and it goes into some detail about the strategy employed:

I'm working with the following facts:

happy(james).
happy(harry).
unhappy(tom).
unhappy(ben).
unhappy(dick).

people([ben, james, harry, tom, dick]).

Your desired end can be achieved with a simple predicate establishing a relationship between a name and the happy/1 and unhappy/1 predicates:

person_happiness(Person, happy(Person))   :- happy(Person).
person_happiness(Person, unhappy(Person)) :- unhappy(Person).

This person_happiness/2 exploits the homoiconic nature of Prolog. The instance of happy/1 appearing in the rule's body is a call to the predicate, and it is true just in case Person can be unified in a call to the fact happy/1. The instance of happy/1 occurring in the second argument of person_happiness/2 functions as a data structure, and essentially works to label Person as happy. This second argument could be replaced with happy-Person, happy/Person, happy=Person, emotion(Person, happy), and many other things besides.

With this predicate alone, we can generate a report of all the happy and unhappy people by backtracking over free variables:

?- person_happiness(Person, Happiness).
Person = james,
Happiness = happy(james) ;
Person = harry,
Happiness = happy(harry) ;
Person = tom,
Happiness = unhappy(tom) ;
Person = ben,
Happiness = unhappy(ben) ;
Person = dick,
Happiness = unhappy(dick).

We can also find the Happiness for a particular person:

?- person_happiness(dick, Happiness).
Happiness = unhappy(dick).

And we can find all the people who share a common quality:

?- person_happiness(Person, happy(Person)).
Person = james ;
Person = harry.

The queries above work just by consulting the facts happy/1 and unhappy/2, but you want to check these facts against the names in your list. We can use member/2 in conjunction with person_happiness/2 to achieve everything you want with backtracking:

?- people(Ps), member(P, Ps), person_happiness(P, PH).
Ps = [ben, james, harry, tom, dick],
P = ben,
PH = unhappy(ben) ;
Ps = [ben, james, harry, tom, dick],
P = james,
PH = happy(james) ;
Ps = [ben, james, harry, tom, dick],
P = harry,
PH = happy(harry) ;
Ps = [ben, james, harry, tom, dick],
P = tom,
PH = unhappy(tom) ;
Ps = [ben, james, harry, tom, dick],
P = dick,
PH = unhappy(dick).

To get all of these results in one go, we can use maplist/3 to apply person_happiness/2 to each member of the People in people(People):

?- people(People), maplist(person_happiness, People, PeopleHappiness).
People = [ben, james, harry, tom, dick],
PeopleHappiness = [unhappy(ben), happy(james), happy(harry), unhappy(tom), unhappy(dick)] 


标签: list prolog