How can I assert facts about all List members in Prolog? - prolog

I'd like to assert facts about all members of a List in prolog, and have any resulting unification retained. As an example, I'd like to assert that each list member is equal to five, but none of the below constructs does this:
?- L=[X,Y,Z], forall(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
?- L=[X,Y,Z], foreach(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
I would like a way to pose the query such that X=5,Y=5, and Z=5.

There is a lot of terminology that you might be getting wrong, or I am misunderstanding you.
"Equal to" is not the same as "could unify", or "unify", but it depends how you mean it.
With SWI-Prolog, from the top level:
?- X == 5.
false. % the free variable X is not the integer 5
?- unifiable(X, 5, U).
U = [X=5]. % you could unify X with 5, then X will be 5
?- X = 5.
X = 5. % X unifies with 5 (and is now bound to the integer 5)
The comment by CapelliC already has the answer that you are most likely after: given a list of variables (either free or not), make so that each variable in the list is bound to the integer 5. This is best done by unification (the third query above). The maplist simply applies the unification to each element of the list.
PS. In case you are wondering how to read the maplist(=(5), L):
These three are equivalent:
maplist(=(5), [X,Y,Z])
maplist(=, [5,5,5], [X,Y,Z])
X=5, Y=5, Z=5
And of course X=5 is the same as =(X,5).

Related

Prolog internal variable names

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

Prolog - adding two arguments, even if one is not a number

in Prolog, how should I proceed when I want to add two arguments, even if one is not a number. So for instance, if I enter add2args(1,2,R). the result should be R = 3. If I enter add2args(1,x,R). the result should be R=1+x.
So far I have this:
add_2args(X,Y,R):- number(X),number(Y), R is (X+Y).
Which allows me to add two numbers, but I don't know how I can get it to print out anything other than true and false if X and Y are not numbers which is normal since number(X) checks if X is a number or not. What other rule do I have to add to get the desired result?
Prolog will view an expression symbolically (as a Prolog term) unless explicitly evaluated with something like is/2. So the simplest way to do this in your case would be the following:
add_2args(X, Y, R) :-
( number(X), number(Y) % Both X and Y are numbers, then...
-> R is X + Y % Evaluate the expression
; R = X + Y % Else, just unify R with the expression
).
The R = X + Y will not evaluate the expression but only unify the term X + Y with R. This is also a nice "Prolog beginner's guide" illustration for the difference between =/2 and is/2. If you wrote, for example, R = 2 + 3, then did a write(R) you would see 2 + 3, not 5. You could subsequently do, Result is R which would then evaluate the expression R and yield Result = 5.
| ?- R = 2 + 3, Result is R.
R = 2+3
Result = 5
yes
| ?-

Prolog Set List's Head

append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.

What is best practices in Prolog when assigning a number to a variable?

To illustrate the difference between 'is' and '=', next example is given in my Prolog course:
?- X is 2+3
X = 5.
?- X = 2+3.
X = 2+3.
However, both Y is 3 and Y = 3 seem to do the same. Is there a difference? And if not, is there a convention not to use one of the two in Prolog programs?
In Prolog, =/2 and is/2 serve very different purposes. is/2 is used to assign a value from an arithmetic expression. The right hand side must be fully instantiated (all variables bound) and it will compute the expression and unify it with the single variable on the left. For example:
Y = 3,
X is log(Y+7)/2.
X = 1.151292546497023
Y = 3
The = is used to unify terms on each side of the =. So when you say:
X = log(Y+7)/2.
That is unifying the term X with the term log(Y+7)/2 (or, technically, '/'(log('+'(Y,7),2)) which gives you X = log(Y+7)/2. It doesn't compute log(Y+7)/2. because that's not the job of =. That's a job for is/2.
With = you can also say things like:
foo(X, _) = foo(3, blah).
And you will get X = 3 since it can unify both terms by setting X to 3.
In the simplest case, these operators appear to be the same because X is 3 evaluates the expression 3 and assigns it (binds it to) X, and X = 3 unifies X with 3. Both results are the same in this case.

prolog function returning memory locations instead of values

just started programming with prolog and I'm having a few issues. The function I have is supposed to take a value X and copy it N number of times into M. My function returns a list of N number of memory locations. Here's the code, any ideas?
duple(N,_,M):- length(M,Q), N is Q.
duple(N,X,M):- append(X,M,Q), duple(N,X,Q).
Those are not memory adresses. Those are free variables. What you see is their internal names in your prolog system of choice. Then, as #chac pointed out (+1 btw), the third clause is not really making sense! Maybe you can try to tell us what you meant so that we can bring light about how to do it correctly.
I'm going to give you two implementations of your predicate to try to show you correct Prolog syntax:
duple1(N, X, L) :-
length(L, N),
maplist(=(X), L).
Here, in your duple1/3 predicate, we tell prolog that the length of the resulting list L is N, and then we tell it that each element of L should be unified with X for the predicate to hold.
Another to do that would be to build the resulting list "manually" through recursion:
duple2(0, _X, []).
duple2(N, X, [X|L]) :-
N > 0,
NewN is N - 1,
duple1(NewN, X, L).
Though, note that because we use >/2, is and -/2, ie arithmetic, we prevent prolog from using this predicate in several ways, such as:
?- duple1(X, Y, [xyz, xyz]).
X = 2,
Y = xyz.
This worked before, in our first predicate!
Hope this was of some help.
I suppose you call your predicate, for instance, in this way:
?- duple(3,xyz,L).
and you get
L = [_G289, _G292, _G295] ;
ERROR: Out of global stack
If you try
?- length(X,Y).
X = [],
Y = 0 ;
X = [_G299],
Y = 1 ;
X = [_G299, _G302],
Y = 2 ;
X = [_G299, _G302, _G305],
Y = 3 ;
X = [_G299, _G302, _G305, _G308],
Y = 4 .
...
you can see what's happening:
your query will match the specified *M*, displaying a list of M uninstantiated variables (memory locations), then continue backtracking and generating evee longer lists 'til there is stack space. Your second rule will never fire (and I don't really understand its purpose).
A generator is easier to write in this way:
duple(N,X,M) :- findall(X,between(1,N,_),M).
test:
?- duple(3,xyz,L).
L = [xyz, xyz, xyz].

Resources