Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prolog internal variable names

Tags:

prolog

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 ?

like image 319
Marwan Ihab Avatar asked Feb 14 '26 04:02

Marwan Ihab


1 Answers

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 ?
...
like image 118
tas Avatar answered Feb 17 '26 21:02

tas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!