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