Prolog-使用Bagof

Prolog-使用Bagof,prolog,prolog-setof,Prolog,Prolog Setof,我在准备考试的时候,一直被过去的一道纸题难住了 问题是: 我想我必须使用findall/bagof/setof,因为我需要收集一组解决方案。此外,setof似乎是合适的,因为列表需要按降序显示 到目前为止,我的解决方案是: teams(List) :- setof((Team, A), (Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1), List). 然而问题是,我并没有在一个列表中找到所有答

我在准备考试的时候,一直被过去的一道纸题难住了

问题是:

我想我必须使用
findall/bagof/setof
,因为我需要收集一组解决方案。此外,
setof
似乎是合适的,因为列表需要按降序显示

到目前为止,我的解决方案是:

teams(List) :- 
    setof((Team, A), 
    (Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1), 
    List).
然而问题是,我并没有在一个列表中找到所有答案。我很可能错误地使用了Team^。我真的很感激有人给我指点,告诉我如何得到按点排列的有序元组列表。它给我的输出是:

X = [(queenspark,43)] ? ;
X = [(stirling,26)] ? ;
X = [(clyde,25)] ? ;
X = [(peterhead,35)] ? ;
X = [(rangers,63)] ? ;
而且,如果有什么样的顺序,也不太清楚,所以我也不知道
setof
是如何排序的

使用setof解决这个问题的最佳方法是什么


谢谢。

首先,我建议将
(团队,A)
更改为成对表示法
A-Team
,其中
A
位于前面,因为这是团队的总分,因此是要用于排序的键。然后,您希望在不应在列表中的变量前加上前缀,在要聚合的查询前面加上
^
。请参见以下示例:

   ?- setof(A-Team, P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), List).
List = [25-clyde,26-stirling,35-peterhead,43-queenspark,63-rangers]

由于您的要求,考虑下面的查询,将查询顺序翻转到<代码> Tea-A//C>作为比较原因:

   ?- setof(Team-A,P^Wins^Draws^L^(team(Team,P,Wins,Draws,L), A is Wins*3 + Draws*1),List).
List = [clyde-25,peterhead-35,queenspark-43,rangers-63,stirling-26]
现在,结果列表按照团队名称进行排序。因此,
A-Team
是合适的选择。然后,您可以使用谓词列表:reverse/2将顺序反转为降序列表,然后定义辅助谓词对_second/2,您可以将其与apply:maplist/3一起使用,以消除对中的前导分数:

:- use_module(library(lists)).
:- use_module(library(apply)).

% team(+Name, +Played, +Won, +Drawn, +Lost)
team(clyde,26,7,4,15).
team(peterhead,26,9,8,9).
team(queenspark,24,12,7,5).
team(rangers,26,19,6,1).
team(stirling,25,7,5,13).

pair_second(A-B,B).    % 2nd argument is 2nd element of pair

teams(Results) :- 
   setof(A-Team, 
         P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), 
         List),
   reverse(List,RList),
   maplist(pair_second,RList,Results). % apply pair_second/2 to RList
如果现在查询谓词,则会得到所需的结果:

   ?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]
关于你在评论中的问题:是的,当然有可能。您可以编写一个谓词来描述对列表和仅由对的第二个元素组成的列表之间的关系。让我们称之为pairlist_namelist/2:

pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
   pairlist_namelist(SNs,Ns).
然后您可以这样定义团队/1:

teams(Results) :- 
   setof(A-Team, 
         P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), 
         List),
   reverse(List,RList),
   pairlist_namelist(RList,Results).

在这种情况下,除了maplist/3之外,您也不需要pair_second/2。另外,您不需要包括
:-使用_模块(库(应用))。
上面的示例查询产生与此版本相同的结果。

首先,我建议更改
(团队,A)
到成对表示法
a-Team
,其中
a
位于前面,因为这是团队的总分,因此是您要用于排序的关键。然后,您希望在不应在列表中的变量前加上前缀,在要聚合的查询前面加上
^
。请参见以下示例:

   ?- setof(A-Team, P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), List).
List = [25-clyde,26-stirling,35-peterhead,43-queenspark,63-rangers]

由于您的要求,考虑下面的查询,将查询顺序翻转到<代码> Tea-A//C>作为比较原因:

   ?- setof(Team-A,P^Wins^Draws^L^(team(Team,P,Wins,Draws,L), A is Wins*3 + Draws*1),List).
List = [clyde-25,peterhead-35,queenspark-43,rangers-63,stirling-26]
现在,结果列表按照团队名称进行排序。因此,
A-Team
是合适的选择。然后,您可以使用谓词列表:reverse/2将顺序反转为降序列表,然后定义辅助谓词对_second/2,您可以将其与apply:maplist/3一起使用,以消除对中的前导分数:

:- use_module(library(lists)).
:- use_module(library(apply)).

% team(+Name, +Played, +Won, +Drawn, +Lost)
team(clyde,26,7,4,15).
team(peterhead,26,9,8,9).
team(queenspark,24,12,7,5).
team(rangers,26,19,6,1).
team(stirling,25,7,5,13).

pair_second(A-B,B).    % 2nd argument is 2nd element of pair

teams(Results) :- 
   setof(A-Team, 
         P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), 
         List),
   reverse(List,RList),
   maplist(pair_second,RList,Results). % apply pair_second/2 to RList
如果现在查询谓词,则会得到所需的结果:

   ?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]
关于你在评论中的问题:是的,当然有可能。您可以编写一个谓词来描述对列表和仅由对的第二个元素组成的列表之间的关系。让我们称之为pairlist_namelist/2:

pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
   pairlist_namelist(SNs,Ns).
然后您可以这样定义团队/1:

teams(Results) :- 
   setof(A-Team, 
         P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), 
         List),
   reverse(List,RList),
   pairlist_namelist(RList,Results).

在这种情况下,除了maplist/3之外,您也不需要pair_second/2。另外,您不需要包含
:-使用_模块(库(应用))。
上面的示例查询产生与此版本相同的结果。

谢谢!有没有办法不用地图列表来回答这个问题?我们的课堂幻灯片上并没有提到这个问题(我们现在正在学习序言),所以我不确定考试是否允许。我们绝对不能在考试中使用外部模块,这是肯定的。我从你的代码中得到了灵感。非常感谢你教我使用
A-B
的巧妙技巧!不知道这是可能的,这使得排序变得容易多了。再次感谢。@user3186023:我更新了我的答案以解决您的问题;-)是的,定义的
pairlist\u namelist
与您非常相似,并且输出似乎是正确的。再次感谢。关于
^
操作员如何在
bagof/setof
中工作,您有可靠的消息来源吗?LPN似乎只是浏览了一下,没有很好地解释它,所以我一直在使用它。@user3186023:我发现理查德·奥基夫的《Prolog技巧》第11章是一本关于寻找所有解决方案的非常好的书。谢谢!有没有办法不用地图列表来回答这个问题?我们的课堂幻灯片上并没有提到这个问题(我们现在正在学习序言),所以我不确定考试是否允许。我们绝对不能在考试中使用外部模块,这是肯定的。我从你的代码中得到了灵感。非常感谢你教我使用
A-B
的巧妙技巧!不知道这是可能的,这使得排序变得容易多了。再次感谢。@user3186023:我更新了我的答案以解决您的问题;-)是的,定义的
pairlist\u namelist
与您非常相似,并且输出似乎是正确的。再次感谢。关于
^
操作员如何在
bagof/setof
中工作,您有可靠的消息来源吗?LPN似乎只是浏览了一下,没有很好地解释它,所以我一直在使用它。@user3186023:我发现理查德·奥基夫的《Prolog技巧》第11章是一本关于寻找所有解决方案的非常好的书。