我的文件 (position(M,P))
中已有大量事实,M 是玩家的名字,P 是玩家的位置,我被要求做a player_list(L,N)
,L是玩家列表,N是这个列表的大小。我做到了,它起作用了,问题是它给出的列表没有名字,它给我的是数字而不是名字
player_list([H|T],N):- L = [H|T],
position(H,P),
\+ member(H,L),
append(L,H),
player_list(T,N).
我得到的是:
?- player_list(X,4).
X = [_9176, _9182, _9188, _9194] .
那我该怎么办?
最佳答案
您可以使用附加列表作为参数来跟踪您已有的玩家。这个列表一开始是空的,所以调用谓词调用描述与 []
的实际关系的谓词作为附加参数:
player_list(PLs,L) :-
pl_l_(PLs,L,[]). % <- actual relation
您发布的定义缺少一个基本案例,也就是说,如果您已经拥有所需数量的玩家,则可以停止添加其他玩家。在这种情况下,要添加的玩家数量为零,否则大于零。你还必须描述列表的头部(PL
)是一个玩家(你不关心他的位置,所以变量前面有一个下划线(_P
), 否则目标就像在你的代码中一样) 并且不在累加器中 (与你的代码相反, 你检查 PL
是否不在 L
中) 但在递归调用中它在累加器中。您可以通过在递归目标中包含 [PL|Acc0]
来实现后者,因此您不需要 append/2
。将所有这些放在一起,您的代码可能如下所示:
pl_l_([],0,_). % base case
pl_l_([PL|PLs],L1,Acc0) :-
L1 > 0, % number of players yet to add
L0 is L1-1, % new number of players to add
position(PL,_P), % PL is a player and
\+ member(PL,Acc0), % not in the accumulator yet
pl_l_(PLs,L0,[PL|Acc0]). % the relation holds for PLs, L0 and [PL|Acc0] as well
关于您的评论,我认为您的代码包含以下四个事实:
position(zlatan,center).
position(rooney,forward).
position(ronaldo,forward).
position(messi,forward).
然后您的示例查询会产生所需的结果:
?- player_list(X,4).
X = [zlatan,rooney,ronaldo,messi] ? ;
X = [zlatan,rooney,messi,ronaldo] ? ;
...
如果您还打算以相反的方式使用谓词,我建议使用 CLP(FD)。要了解原因,请考虑最一般的查询:
?- player_list(X,Y).
X = [],
Y = 0 ? ;
ERROR at clause 2 of user:pl_l_/3 !!
INSTANTIATION ERROR- =:=/2: expected bound value
您收到此错误是因为 >/2
期望两个参数都为基础。您可以像这样修改谓词 pl_l_/3
以使用 CLP(FD):
:- use_module(library(clpfd)).
pl_l_([],0,_).
pl_l_([PL|PLs],L1,Acc0) :-
L1 #> 0, % <- new
L0 #= L1-1, % <- new
position(PL,_P),
\+ member(PL,Acc0),
pl_l_(PLs,L0,[PL|Acc0]).
通过这些修改,谓词更加通用:
?- player_list([zlatan,messi,ronaldo],Y).
Y = 3
?- player_list(X,Y).
X = [],
Y = 0 ? ;
X = [zlatan],
Y = 1 ? ;
X = [zlatan,rooney],
Y = 2 ?
...
关于Prolog 内部变量名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44749504/