filter - 如何在 Prolog 中过滤具有多个条件的列表?
问题描述
我可以通过以下步骤根据 1 个条件过滤列表:
- 建立列表
findall
- 用于
include
隔离符合条件的元素。
但是当有多个条件要尊重时如何进行?在这种特殊情况下,条件的数量和条件本身是未知的,因此谓词必须适用于所有上下文。
下面是一个如何构建条件以及如何调用它们的示例:
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).
解决方案
您没有说“所有上下文”是如何表示的,但是,因为include/3
将1 个参数的通用目标作为第一个参数(更准确地说,该目标的名称),您可以相应地构建该目标。
例如,如果您需要实现列表中的一系列单参数目标,则:
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/1
和odd/1
被notprime/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.