prolog匹配从列表到谓词

时间:2018-06-07 12:02:33

标签: list prolog matching predicate

我是prolog的新手,并尝试解决我的问题后面的问题。

我有一些人

person(john, 36).
person(jane, 3).
person(amber, 32).
person(emmy, 2).
person(clement, 37).
person(patrick, 15).
person(emilie, 20).

我有一份代表食物的化合物清单可以是健康的(好的)。

foods([food(frechfries, _), food(apple, good), food(burger,_),
    food(kiwi, good), food(banana, good), food(potato, good), food(orange, good),
    food(cereal, good), food(hotdog, _), food(steak, _), food(coca, _), food(water, good)]).

我想将每个项目与一个人匹配,向每个人分发一个且仅一个食物。为此,我有以下规则:

distribute(P, F, Results) :- person(P, _), findall(Item, memberchk(Item, F), Results).

不幸的是,每个人都会收到列表中的第一项

Output

如果我尝试使用此规则删除已使用的项目:

distribute(P, F, Results) :- person(P, _), findall(Item, memberchk(Item, F), Results), delete(F, Item, F).

我得到了相同的结果。任何人都能看到我失踪的东西?

1 个答案:

答案 0 :(得分:0)

一般来说,听起来你有两个事实集合,你只想为每个唯一匹配对定义一个成功的规则。

事实的集合是personfood。正如我在评论中提到的那样,将食物定义为具有列表的单一事实将会有点尴尬。我会像定义food一样定义person,也就是说,作为个别事实。

person(john, 36).
person(jane, 3).
person(amber, 32).
person(emmy, 2).
person(clement, 37).
person(patrick, 15).
person(emilie, 20).

food(frechfries, _).
food(apple, good).
food(burger,_).
food(kiwi, good).
food(banana, good).
food(potato, good).
food(orange, good).
food(cereal, good).
food(hotdog, _).
food(steak, _).
food(coca, _).
food(water, good).

现在我们可以考虑定义一场比赛。你可以这样想:

  

成功的配对包括一个人 - 食物对的列表,其中每个人和每个食物只出现一次(从各自的集合中唯一选择)并且每个人都有代表。

由于我们试图独特地选择每个人和食物,我认为select/3将是一个很好的选择,作为实现预期目标的核心机制。

person_food_pairs(PeopleFoodPairings) :-
    findall(Person, person(Person, _), People),
    findall(Food, food(Food, _), Foods),
    length(People, NumberOfPeople),
    length(Foods, NumberOfFoods),
    NumberOfPeople =< NumberOfFoods,
    person_food_pairing(People, Foods, PeopleFoodPairings).

person_food_pairing([], _, []).
person_food_pairing(People, Foods, [Person-Food|RemainingPairs]) :-
    select(Person, People, RemainingPeople),
    select(Food, Foods, RemainingFoods),
    person_food_pairing(RemainingPeople, RemainingFoods, RemainingPairs).

会有很多组合,所以有很多解决方案!我没有看到任何其他限制这种情况的条件。此外,您可以省略这一行,由于person_food_pairing/2的定义,代码仍会产生相同的结果:

    length(People, NumberOfPeople),
    length(Foods, NumberOfFoods),
    NumberOfPeople =< NumberOfFoods,

然而,代码会做很多不必要的执行,最终确定它不能进行配对。所以这些行有助于尽早确定这种情况。

<小时/> 如果,如评论中所述,您的条件涉及某些人和食物属性,则您需要随身携带这些属性,直到您进行配对。

person_food_pairs(PeopleFoodPairings) :-
    findall(Person-Age, person(Person, Age), People),  % Include age
    findall(Food-Health, food(Food, Health), Foods),   % Include health factor
    length(People, NumberOfPeople),
    length(Foods, NumberOfFoods),
    NumberOfPeople =< NumberOfFoods,
    person_food_pairing(People, Foods, PeopleFoodPairings).

person_food_pairing([], _, []).
person_food_pairing(People, Foods, [Person-Food|RemainingPairs]) :-
    select(Person-Age, People, RemainingPeople),  % Select person-age pair
    select(Food-Health, Foods, RemainingFoods),   % Select food-health pair
    (Age < 20 -> Health == good ; true),          % Condition to include
    person_food_pairing(RemainingPeople, RemainingFoods, RemainingPairs).

请注意此处使用==/2而不是统一=/2。原因是您希望_good不匹配。如果使用统一,则Prolog将成功将变量_与原子good统一起来。另一方面,==/2检查这两个术语是否真的相同且不统一。