如何用Prolog生成包含变量所有实例的列表?
在Prolog中生成变量所有实例的列表
需求与示例
现有Prolog事实定义:
entree( 'foie gras' ). entree( 'salade gourmande' ). entree( 'crudites' ).
需要实现谓词generateliste(L),使得调用后L等于['foie gras','salade gourmande','crudites'],即包含entree的所有实例。
尝试的代码及问题
我写了这段代码:
generateliste(E,[E|R]):-entree(E),not(member(E,R)),generateliste(E,R).
但它无法运行,一是缺少递归终止的基例,二是逻辑上存在问题(递归时重复绑定变量E,且member(E,R)的检查方向不对)。
解决方案
方法1:用内置谓词findall/3(推荐)
Prolog内置的findall/3专门用来收集所有满足目标的实例到列表中,写法最简单:
generateliste(L) :- findall(Entree, entree(Entree), L).
直接调用generateliste(L).,就会得到L = ['foie gras', 'salade gourmande', 'crudites']。
方法2:手动实现递归收集
如果不想依赖内置谓词,手动写递归逻辑需要注意终止条件和避免重复收集:
实现1(基于成员检查去重)
% 基例:当没有未被收集的entree实例时,列表为空 generateliste([]) :- \+ entree(_). % 递归步骤:取一个不在子列表中的实例,加入列表后继续收集剩余实例 generateliste([E|Rest]) :- entree(E), generateliste(Rest), \+ member(E, Rest).
调用时会生成所有不重复的实例列表,即使entree有重复事实也能去重。
实现2(借助setof/3自动去重排序)
如果需要自动去重并排序结果,可以用setof/3:
generateliste(L) :- setof(E, entree(E), L).
注意setof/3会对结果排序,若不需要排序,优先用findall/3。
内容的提问来源于stack exchange,提问作者SBAT
相关产品推荐
相关产品推荐

