Prolog - 使用 Bagof

Prolog - Using Bagof

我在备考时一直卡在过去的试卷问题上。

问题是:

https://gyazo.com/ee2fcd88d67068e8cf7d478a98f486a0

我想我必须使用 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 解决这个问题的最佳方法是什么?

谢谢。

首先,我建议将 (Team,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]

既然你问了,考虑下面的查询,为了比较的原因,对排序翻转到 Team-A

   ?- 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是个恰到好处的选择。然后,您可以使用谓词 lists:reverse/2 将顺序反转为降序列表,然后定义一个辅助谓词 pair_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).

然后你可以这样定义teams/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。您也不需要包含 :- use_module(library(apply)). 上面的示例查询与此版本产生相同的结果。