序言将列表中的项目匹配到谓词

prolog match items from list to predicates

我是 prolog 的新手,正在尝试解决我在 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).

我得到了同样的结果。有人看到我遗漏了什么吗?

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

事实集是 personfood。正如我在评论中提到的,将食物定义为带有列表的单一事实会有点尴尬。我会像定义 person 一样定义 food,即,作为单独的事实。

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).

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

A successful match-up consists of a list of person-food pairs in which the each person and each food only appear once (are uniquely selected from the respective collections) and each person is represented.

由于我们试图 select 每个人和食物都是独一无二的,我认为 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,另一方面,检查这两个术语是否真的相同并且不做统一。