3

I have a large numbers of facts that are already in my file (position(M,P)), M is the name and P is the position of the player , I am asked to do a player_list(L,N), L is the list of players and N is the size of this list. I did it and it works the problem is that it gives the list without the names it gives me numbers and not names

player_list([H|T],N):-  L = [H|T],
                   position(H,P),
                   \+ member(H,L),
                   append(L,H),
                   player_list(T,N).

what I get is:

?- player_list(X,4).
  X = [_9176, _9182, _9188, _9194] .

so what should I do ?

  • 2
    How is position/2 defined? And what's the desired result of the query `player_list(X,4).`? – tas Jun 25 '17 at 19:36
  • postion/2 is defined as a data predicate for example postion(Zlatan,Center). so i have a large numbers of this predicate what i want to get from the query is for example : X = [zlatan, Rooney, Ronaldo, Messi] not the numbers – Marwan Ihab Jun 25 '17 at 20:06

1 Answers1

4

You could use an additional list as an argument to keep track of the players you already have. This list is empty at the beginning, so the calling predicate calls the predicate describing the actual relation with [] as an additional argument:

player_list(PLs,L) :-
   pl_l_(PLs,L,[]).            % <- actual relation

The definition you posted is missing a base case, that is, if you already have the desired amount of players, you can stop adding others. In this case the number of players to add is zero otherwise it is greater than zero. You also have to describe that the head of the list (PL) is a player (whose position you don't care about, so the variable is preceded by an underscore (_P), otherwise the goal is just like in your code) and is not in the accumulator yet (as opposed to your code, where you check if PL is not in L) but in the recursive call it is in the accumulator. You can achieve the latter by having [PL|Acc0] in the recursive goal, so you don't need append/2. Putting all this together, your code might look something like this:

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

With respect to your comment, I assume that your code contains the following four facts:

position(zlatan,center).
position(rooney,forward).
position(ronaldo,forward).
position(messi,forward).

Then your example query yields the desired results:

   ?- player_list(X,4).
X = [zlatan,rooney,ronaldo,messi] ? ;
X = [zlatan,rooney,messi,ronaldo] ? ;
...

If you intend to use the predicate the other way around as well, I suggest the use of CLP(FD). To see why, consider the most general query:

   ?- player_list(X,Y).
X = [],
Y = 0 ? ;
     ERROR at  clause 2 of user:pl_l_/3 !!
     INSTANTIATION ERROR- =:=/2: expected bound value

You get this error because >/2 expects both arguments to be ground. You can modify the predicate pl_l_/3 to use CLP(FD) like so:

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

With these modifications the predicate is more versatile:

   ?- player_list([zlatan,messi,ronaldo],Y).
Y = 3

   ?- player_list(X,Y).
X = [],
Y = 0 ? ;
X = [zlatan],
Y = 1 ? ;
X = [zlatan,rooney],
Y = 2 ?
...
tas
  • 8,100
  • 3
  • 14
  • 22
  • I tried it and it worked thank you but one more question could you please clarify what this CLP(FD) library is and what it does as I have said I am new to this so excuse my ignorance. – Marwan Ihab Jun 25 '17 at 22:35
  • 3
    @MarwanIhab for starters, see [CLP(FD) Constraint Logic Programming over Finite Domains](http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html) – lurker Jun 26 '17 at 01:09
  • 1
    I wonder how you think a newbie would be able to properly use CLP(FD) when he doesn't know what to qualify a variable in a query means. In other words, why you don't even suggest findall/3, setof/3 or the like ? – CapelliC Jun 26 '17 at 06:05
  • 3
    @MarwanIhab: In addition to the tutorial pointed out by lurker I can also recommend the [chapter on CLP(FD)](https://www.metalevel.at/prolog/clpfd) from [The Power of Prolog](https://www.metalevel.at/prolog) and the SWI-Prolog Manual's [entry on CLP(FD).](http://www.swi-prolog.org/man/clpfd.html) – tas Jun 26 '17 at 08:10
  • 2
    @CapelliC: I can see your point about CLP(FD), that is why my post starts with a version using `>/2` and `is/2`. My intention was to point out the limitation of that approach and subsequently offer a possible alternative. But of course it's just an option. – tas Jun 26 '17 at 08:18
  • 1
    @CapelliC: Concerning `setof/3` and `findall/3`, I'm not sure that they are so much more easier to comprehend from a newbie perspective, especially with regard to the behaviour of the latter (see [this recent post](https://stackoverflow.com/questions/44728306/findall-3-creates-new-unrelated-variables-in-its-resulting-list)). I also don't see how those predicates would be more helpful in the context of this question but maybe you have something in mind I don't see. I'm certainly open to suggestions :-) – tas Jun 26 '17 at 08:19
  • I think that N is bound to 4 'by accident', probably should be just computed as the result length. If this assumption is true, OP will have an hard time to make sense of the whole. While with findall/3 (that really is the easier construct to grasp for everyone approaching Prolog from imperative languages) would be so easy... – CapelliC Jun 26 '17 at 08:29
  • @CapelliC: Ah, now I see where you're coming from. I interpreted the OP's question exactly the other way around. Firstly, because the example query asks for a list of 4 players and secondly, because the OP indicated in his comment that his code contains a lot of `position/2` facts and: _what i want to get from the query is for example : X = [zlatan, Rooney, Ronaldo, Messi] not the numbers_. – tas Jun 26 '17 at 08:58