我正在学习序言,并尝试从所做的声明中返回名称列表。
例子:
person(sam).
person(tom).
person(holly).
我想返回亲自宣布的任何人的名字。我尝试这样做:
people([]).
people([X | XS]) :-
person(X),
people(XS).
它的工作原理是,添加sam
到列表中,然后sam
无限添加,而不是切换到tom
,然后holly
再结束。有人能指出我正确的方向吗?
例如,您可以使用member/2
和累加器来解决此问题:
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
的列表:
?- findall(X,person(X),L).
L = [sam, tom, holly].
还有其他保证唯一性的高阶谓词,等等。
请注意,findall/3
和我们自己的people/1
方法在语义上并不等效。确实,如果您的数据库包含一个人两次,那么在的包中它将是两次findall/3
。此外,我们自己people/1
将以各种可能的顺序枚举列表。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句