我正在学习prolog,我正试图从我所做的声明中返回一个名单.
例:
person(sam). person(tom). person(holly).
我想要归还任何亲自申报的人的姓名.我试过这样做:
people([]). people([X | XS]) :- person(X), people(XS).
它有效,有点,它添加sam
到列表,然后sam
无限增加而不是切换tom
,然后holly
然后结束.有人能指出我正确的方向吗?
例如,您可以使用a member/2
和accumulator 来解决此问题:
people(L) :- people([],L). people(L,[X|R]) :- person(X), \+member(X,L), people([X|L],R). people(L,[]) :- \+ (person(X),\+ member(X,L)).
或者,如果你知道如何使用cut(!
),你可以使用@ CapelliC的版本:
people(L) :- people([],L). people(L,[X|R]) :- person(X), \+member(X,L), !, people([X|L],R). people(L,L).
因此,每次你寻找一个person/1
X
不是它的成员L
.如果您再也找不到此人,则选择最后一个条款.在这种情况下,空列表[]
向后传播,并且对于调用堆栈上的每个元素,特定X
内容将添加到前面.
findall/3
内置
然而,遵循ISO标准的Prolog变体有内置findall/3
:
findall(+Template, :Goal, -Bag)
您可以按如下方式使用它:
这Template
是你想要获得的数据的仿函数(这可以是变量)X
;
该Goal
是谓词(或谓词的列表等),应该是满意的.Prolog将在内部致电Goal
; 和
Bag
是输出:结果列表.
如果你使用这个:
people(L) :- findall(X,person(X),L).
它将生成所有person/1
s 的列表:
?- findall(X,person(X),L). L = [sam, tom, holly].
还有其他高阶谓词可以保证唯一性等.
语义差异请注意,findall/3
我们自己的people/1
方法在语义上并不相同.实际上,如果你的数据库包含一个人两次,它将是两倍findall/3
.此外,我们自己people/1
将按各种可能的顺序列举列表.