首页 > 解决方案 > 如何在 Prolog 中过滤具有多个条件的列表?

问题描述

我可以通过以下步骤根据 1 个条件过滤列表:

但是当有多个条件要尊重时如何进行?在这种特殊情况下,条件的数量和条件本身是未知的,因此谓词必须适用于所有上下文。

下面是一个如何构建条件以及如何调用它们的示例:

goal(drinkingAge,(person(_,_,A))) :- person(_,_,A), A > 21. %has at least 21 years old

并称他们为一个人:

goal(drinkingAge,(person("Tom",male,24))).

返回true

现在,我可以使用以下条件过滤具有 1 个条件的列表:

findall(person(A,B,C),person(A,B,C),L).
include(goal(drinkingAge), L, ReturnList).

标签: filterprolog

解决方案


您没有说“所有上下文”是如何表示的,但是,因为include/31 个参数的通用目标作为第一个参数(更准确地说,该目标的名称),您可以相应地构建该目标。

例如,如果您需要实现列表中的一系列单参数目标,则:

succeed_all_goals_for_value([],_).
succeed_all_goals_for_value([Goal|Goals],Value) :-
   call(Goal,Value),                         
   succeed_all_goals_for_value(Goals,Value). 

然后include/3就可以调用了。例如,假设number/1odd/1notprime/1定义:

?- include(
       succeed_all_goals_for_value([number,odd,notprime]), 
       List,
       ListFiltered).

使用更具体的goal/2语法

我们现在可以变得更加具体。这是一种可能性,带有plunit测试用例:

% ---
% Helper
% succeed_all_goals(+Goals,+Element). 
% ---

% Trivially succeed if there are no goals

succeed_all_goals([],_). 

% Otherwise go through the goals and succeed each one!
% There are many ways of doing this...

succeed_all_goals([GoalName|GoalNames],Element) :-
   goal(GoalName,Element),
   succeed_all_goals(GoalNames,Element).

% ---
% Call include/3 with a filtering goal
% that checks the conjunction of all conditions
% ---

myfilter(GoalNames,List,ListFiltered) :-   
   include(
      succeed_all_goals(GoalNames),
      List,
      ListFiltered).
      
% ---
% A bit of testing
% ---

% Succeed if second argument is a person who has reached drinking age
goal(drinkingAge, person(_,_,A)) :- A > 21.

% Succeed if second argument is a person who is male
goal(male, person(_,male,_)).

:- begin_tests(myfilter).

test(1) :- 
   myfilter(
      [drinkingAge,male],
      [person(jean,male,22),person(françoise,female,17)],
      ListFiltered),
   assertion(ListFiltered==[person(jean,male,22)]).
   
test(2) :- 
   myfilter(
      [male],
      [person(jean,male,22),person(françoise,female,17)],
      ListFiltered),
   assertion(ListFiltered==[person(jean,male,22)]).

:- end_tests(myfilter).

所以:

?- [greatfilter].
true.

?- run_tests.
% PL-Unit: myfilter .. done
% All 2 tests passed
true.

推荐阅读