0

I've been stuck on a past paper question while studying for my exams.

The question is:

https://gyazo.com/ee2fcd88d67068e8cf7d478a98f486a0

I figured I've got to use findall/bagof/setof because I need to collect a set of solutions. Furthermore, setof seems appropriate because the list needs to be presented in descending order.

My solution so far is:

teams(List) :- 
    setof((Team, A), 
    (Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1), 
    List).

However the problem is I don't quite get the answers all in one list. I'm very likely using Team^ incorrectly. I'd really appreciate pointers on how I can get a list of ordered tuples in terms of points. The output it gives me is:

X = [(queenspark,43)] ? ;
X = [(stirling,26)] ? ;
X = [(clyde,25)] ? ;
X = [(peterhead,35)] ? ;
X = [(rangers,63)] ? ;

Also, it's not really apparent what kind of order, if any it's in, so I'm also lost as to how setof is ordering.

Whats the best way to approach this question using setof?

Thanks.

1 Answers1

2

Firstly, I would suggest to change (Team,A) to a pair representation A-Team with the A being in front since this is the total score of the team and thus the key you want to use for sorting. Then you would like to prefix the variables that should not be in the list with a ^ in front of the query you want to aggregate. See the following example:

   ?- 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]

Since you asked, consider the following query with the pair ordering flipped to Team-A for comparison reasons:

   ?- 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]

Now the resulting list is sorted with respect to the teamnames. So A-Team is the opportune choice. You could then use the predicate lists:reverse/2 to reverse the order to a descending list and then define an auxilary predicate pair_second/2 that you can use with apply:maplist/3 to get rid of the leading scores in the pairs:

:- 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

If you query the predicate now you get the desired results:

   ?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]

Concerning your question in the comments: Yes, of course that is possible. You can write a predicate that describes a relation between a list of pairs and a list than only consists of the second element of the pairs. Let's call it pairlist_namelist/2:

pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
   pairlist_namelist(SNs,Ns).

Then you can define teams/1 like so:

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).

In this case, besides maplist/3, you don't need pair_second/2 either. Also you don't need to include :- use_module(library(apply)). The example query above yields the same result with this version.

tas
  • 8,100
  • 3
  • 14
  • 22
  • Thanks for this! Is there any way to do this question without using maplist? It's not really come up in our lecture slides (we were following Learn prolog Now), so I'm unsure whether it would be allowed in the exam. We definitely can't use external modules in the exam, thats for sure. –  May 15 '16 at 21:57
  • I have got it working with inspiration from your code. Thanks so much for teaching me the neat trick using `A-B`! Did not know that was possible, makes sorting so much easier. Thanks again. –  May 15 '16 at 22:15
  • @user3186023: I updated my answer to address your question ;-) – tas May 15 '16 at 22:18
  • Yep, defined `pairlist_namelist` very similarly to you, and the output seems to be correct. Thanks again. Do you have any credible sources on how the `^` operator works in `bagof/setof`? LPN only seems to glance over it and doesn't explain it too well and so I was stuck using it. –  May 15 '16 at 22:19
  • 1
    @user3186023: I find chapter 11 of *The Craft of Prolog* by Richard O'Keefe to be a very good read on the topic of finding all solutions. – tas May 16 '16 at 00:17