searching in list getting true infinitely in prolog - list

I tried to code a Prolog program that takes 2 value and calculates if the pair is valid or not. If pairs are in different lists, then pairs will be valid and they can make match. If two team in same list(group) then they can't make match which means false.
when i started the program it doesn't show anything. I thought there would be infinite searching or looping. Then tried that simple code
GroupB=[china,usa,chile,italy].
member(X,[X|_]).
member(X,[_|T]):-
member(X,T).
match(X):-
member(X,GroupB).
In that code i saw that program always gives me true. I typed; to SWI-Prolog it gave me another true, i typed ; again another true then i realized that the problem should be in that searching part. Thanks for all interests from now. All suggestions are welcome.
edit:
I edited the code like that to try a different style
GroupA([germany,brazil,turkey,korea]).
GroupB([china,usa,chile,italy]).
member(X,[X|_]).
member(X,[_|T]):-
member(X,T).
memberence(X):-
GroupA(L).
GroupB(M).
member(X,L).
member(X,M).
collision(X,Y):-
GroupA(L),
member(X,L),
member(Y,L).
GroupB(L),
member(X,L),
member(Y,L).
match(X,Y) :-
GroupA(L),
memberence(X),
memberence(Y),
\+collision(X,Y).
now i got:
ERROR: Undefined procedure: match/2
ERROR: However, there are definitions for:
ERROR: catch/3
although there is a match(X,Y) procedure why it gives me undefined match/2 error.
GroupA=[germany,brazil,turkey,korea].
GroupB=[china,usa,chile,italy].
member(X,[X|_]).
member(X,[_|T]):-
member(X,T).
memberence(X):-
member(X,GroupA).
member(X,GroupB).
collision(X,Y):-
member(X,GroupA),
member(Y,GroupA).
member(X,GroupB),
member(Y,GroupB).
match(X,Y) :-
memberence(X),
memberence(Y),
\+collision(X,Y).

a)
You have a dot that must be comma in:
collision(X,Y):-
member(X,GroupA),member(Y,GroupA).
member(X,GroupB),member(Y,GroupB).
b)
Better you do not redefine "member", it is standard.
c)
If I change dot by comma in:
collision(X,Y):-
GroupA(L),member(X,L),member(Y,L),
GroupB(L),member(X,L),member(Y,L).
this statement will fail always because there are no list "L" common to GroupA and GroupB.
d)
If we take what seems the original request "takes 2 value and calculates if the pair is valid or not. If pairs are in different lists, then pairs will be valid and they can make match. If two team in same list(group) then they can't make match which means false."
the solution seems obvious:
match(X,Y) :- groupA(A), member(X,A), groupB(B), member(Y,B).
match(Y,X) :- groupA(A), member(X,A), groupB(B), member(Y,B).

You have 2 big problems.
First, you seem to use . and , interchangeably.
Second, you fail to understand Prolog's scoping rules. Anything that isn't asserted into the prolog database is scoped to the immediate statement or the clause of the predicate of which is a part. If you want somebody to know about it, it either has to be a part of the prolog database or passed as an argument. Thus, when you say something like
GroupB = [china,usa,chile,italy].
The variable GroupB Is unified with the list [china,usa,chile,italy]. At which point, the assertion succeeds, and both the newly-bound variable and the list with which it was unified ** go out of scope** and cease to exist. Then, when you attempt to reference it later on:
GroupB=[china,usa,chile,italy].
.
.
.
match(X) :- member(X,GroupB).
The variable GroupB is unbound. Your implementation of member/2,
GroupB=[china,usa,chile,
member(X,[X|_]) .
member(X,[_|T]) :- member(X,T) .
is more than willing to act in a generative manner when given an unbound variable as its 2nd argument, generating lists of variable, successively (and infinitely) longer on backtracking.

Related

Assign variable in list

I've got a problem with Prolog lists.
Let's say I've got this predicate:
array(p, [A,B,C]).
When I do:
array(p,X).
I got: X = [_,_,_]
Now, considering I've got this predicate:
p1(1) :- array(p1, [1,B1,C1]).
I expected to get:
X = [1,_,_]
but instead, the result is the same as before. Is such a thing even possible in Prolog? Another question is if somehow we can set these values, could we overwrite these values in the same way? I understand that in the prolog variables are assigned only once but I would like to somehow get a dynamic list.
I'm not sure what you mean by "paradigm," and I'm very unclear on what you're trying to do with this code. If you have this at the toplevel:
array(p, [A,B,C]).
you are defining a fact array/2, which associates p with a list of three uninstantiated variables. Your first query amounts to retrieving this fact.
Your second "paradigm" is really the definition of a rule or predicate p1/1, which takes a single argument, which must be 1 for the rule to fire. The body of this second predicate is a call to the predicate array/2 which is definitely going to fail. I don't see how you could possibly get the same result as before, because you defined array(p, ...) before and now you are looking for array(p1, ...). Furthermore, there is no X in your second query, so there is no reason for X to appear in the result, and it definitely would not, even if you had called array(p, ...) instead of array(p1, ...).
I think what you're trying to do here is probably set up some kind of set of three variables and then unify each of them in turn as you proceed along some calculation. To do something like that is possible and easy in Prolog, but the fact database is not going to participate in this process really. You're going to have to write predicates that pass your variables along to other predicates that will unify them and return them bound. None of this is very hard, but it looks like you're going to have to go back and understand the fundamentals here a little better. You're far enough off track here that I don't think anyone can really answer your question as stated, because there's too much confusion in it.

Prolog Member Implemention

I'm trying to implement my own version of member for something I'm working on. As of now it looks like this:
search(X,[X | T]).
search(X, [H | T]) :-
search(X,T).
And it seems to work, however I have a few issues. I get a singleton warning on T and H. Also, I'm just not 100% sure on what the code actually does. From what I understand
search(X,[X | T]).
the first argument is my target, and the second argument is a list split into X and then everything else from list.
Then for
search(X, [H | T]) :-
search(X,T).
I'm not really sure what is happening, besides it calling itself recursively. How does it actually know it's in the list? Any clarification would be appreciated.
EDIT: I think I get it now.
I'm saying the first line is true when the list just contains my target as a fact. Then, I recursively go through the list until the only thing that remains is my target, in which case it's true. If the list ends up empty that it would be false. Is this correct?
The key to understanding Prolog is to grok the declarative reading of the code. So forget how it's going to work for now and just think about what is logically being said.
search(X, [X|T]).
This says
search(X, [X|T]) is true if the first argument and the first item of the second argument are the same
The "if" portion there is just how the pattern matching works. You get a singleton variable warning because you never used T. Prolog would rather you wrote search(X, [X|_]).
The second line says
search(X, [H|T]) is also true if search(X, T) is true.
Your other singleton variable warning is here because you made a variable H and then didn't do anything with it, so Prolog would prefer to see search(X, [_|T]) :- search(X, T)..
Hope this helps!
The accepted answer is great, I just want to clarify some things you added in your edit:
I'm saying the first line is true when the list just contains my target as a fact. Then, I recursively go through the list until the only thing that remains is my target, in which case it's true. If the list ends up empty that it would be false. Is this correct?
The parts "... is true when the list just contains my target" and "until the only thing that remains is my target" (emphasis mine) are incorrect and suggest a small misunderstanding.
Rather, search(a, [a, b, c]) is true because the target is the first element of the list in the second argument. Here a is not "the only thing that remains" in the list. It is just something that appears in the list in addition to other things that we don't need to care about.
You are correct about the last part: Yes, the search fails when it reaches the end of the list.

Define a rule to determine if a list contains a given member

I have recently started learning prolog, and facing a problem with this question:
Define a rule to determine if a list contains a given member.
I searched all over stack overflow to get some links to understand this problem better and write solutions for it but couldn't find anything. Could anyone of you advice to solve this particular problem?
My Approach:
Iterative over the list and see if your member matches with head:
on(Item,[Item|Rest]). /* is my target item on the list */
on(Item,[DisregardHead|Tail]):-
on(Item,Tail).
Do you think my approach is correct?
What you have is indeed a "correct" implementation. The standard name for a predicate that does that is member/2, and is available (under that name) in any Prolog, and should be quite easy to find once you know its name.
Some things to note however. First, with the classical definition (this is exactly as in "The Art of Prolog" by Sterling and Shapiro, p. 58, and identical to yours):
member_classic(X, [X|Xs]).
member_classic(X, [Y|Ys]) :-
member_classic(X, Ys).
If you try to compile this, you will get singleton errors. This is because you have named variables that appear only once in their scope: the Xs in the first clause and the Y in the second. This aside, here is what the program does:
?- member_classic(c, [a,b,c,x]).
true ;
false.
?- member_classic(c, [c]).
true ;
false.
?- member_classic(X, [a,b,c]).
X = a ;
X = b ;
X = c ;
false.
In other words, with this definition, Prolog will leave behind a choice point even when it is quite obvious that there could not be further solutions (because it is at the end of the list). One way to avoid this is to use a technique called "lagging", as demonstrated by the SWI-Prolog library implementation of member/2.
And another thing: with your current problem statement, it might be that this is considered undesirable behaviour:
?- member_classic(a, [a,a,a]).
true ;
true ;
true ;
false.
There is another predicate usually called member_check/2 or memberchk/2 which does exactly what you have written, namely, succeeds or fails exactly once:
?- memberchk(a, [a,a,a]).
true.
?- memberchk(a, [x,y,z]).
false.
It has, however, the following behaviour when the first argument is a variable that might be undesirable:
?- memberchk(X, [a,b,c]).
X = a. % no more solutions!
There are valid uses for both member/2 and memberchk/2 IMHO (but interestingly enough, some people might argue otherwise).
Yes, your solution is correct and works in all directions. Nice!
Notes:
Your solution is in fact more general than what the task asks for. This is a good thing! The task, in my view, is badly worded. First of all, the first clause is not a rule, but a fact. It would have been better to formulate the task like: "Write a Prolog program that is true if a term occurs in a list." This leaves open other use cases that a good solution will also automatically solve, such as generating solutions.
This common predicate is widely known as member/2. Just like your solution, it also works in all directions. Try for example ?- member(E, Ls).
The name for the predicate could be better. A good naming convention for Prolog makes clear what each argument means. Consider for example: element_list/2, and start from there.

Prolog - Check number of occurences doesn't work as expected

In Prolog:
I have the following function that counts the occurences of a certain element in a list:
%count(L:list,E:int,N:int) (i,i,o)
count([],_,0).
count([H|T],E,C):-H == E,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).
I tested it and it works well. But here comes the problem, I have another function that has to check if "1" occurs less than 2 times in a list.
check(L):-count(L,1,C),C<2.
Whenever I try to check the list [1,1,1,1] for example, the result I get is "true", which is wrong, and I have no idea why. I tried to make some changes, but the function just won't work.
Improve your testing habits!
When testing Prolog code don't only look at the first answer to some query and conclude "it works".
Non-determinism is central to Prolog.
Quite often, some code appears to be working correctly at first sight (when looking at the first answer) but exhibits problems (mainly wrong answers and/or non-termination) upon backtracking.
Coming back to your original question... If you want / need to preserve logical-purity, consider using the following minimal variation of the code #Ruben presented in his answer:
count([],_,0).
count([E|T],E,C) :-
count(T,E,C1),
C is C1+1.
count([H|T],E,C) :-
dif(H,E),
count(T,E,C).
dif/2 expresses syntactic term inequality in a logical sound way. For info on it look at prolog-dif!
It happens because count([1,1,1,1],1,1) is also true! In your last count it can also be matched when H does equal E. To illustrate this, use ; to make prolog look for more answers to count([1,1,1,1],1,R). You'll see what happens.
count([],_,0).
count([E|T],E,C):-
count(T,E,C1),
C is C1+1.
count([H|T],E,C):-
H \= E,
count(T,E,C).
check(L) :-
count(L,1,C),
C < 2.
?- check([1,1,1,1,1]).
false
?- check([1]).
true
second and third clauses heads match both the same sequence. As a minimal correction, I would commit the test
count([],_,0).
count([H|T],E,C):-H == E,!,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).

Prolog: take a list of two elements, return true if and only if the first element is same as second

I'm a newbie prolog programmer, and for an assignment, I have to have a basic program that succeeds if and only if list X is a list of two elements, with the first as the same as the second.
From my view of prolog, programs seem to be pretty small, so I typed this in:
firstPair(x,x).
When I run it under swipl, I get this as output:
Syntax error: Operator expected
Is there something more that needs to be done? I thought that if I executed this with say, firstPair(1,2). this would be all it would need to know that it is false.
First, lowercase x is not a variable, it's an atom. Make x uppercase to fix the problem:
firstPair(X,X).
Second, you do not type this into the interpreter. Rather, you write it into a file firstPair.pl, and then read that file into Prolog.
At the command prompt, type this:
['firstPair.pl'].
Press enter. Now you can use your firstPair/2 rule.
Finally, since the assignment talks about lists, I think the instructor wanted you to write firstPair/1, not firstPair/2:
firstPair([X,X]).
Your program/fact
firstPair(X,X).
will succeed if the two arguments given it can be unified, whether they are lists, atoms, variables, etc. To meet your specification, a
program that succeeds if and only if list X is a list of two elements,
with the first as the same as the second.
You need something like this:
list_of_two_elements( [X,X] ).
This will succeed if passed a single term that is (or can be unified with) a list of two elements that are, or can be made through unification, identical. For instance, all of the following will succeed:
list_of_two_elements( X ).
on success, the variable X will be unified with a list of two elements containing the same unbound variable, something like [V1,V1].
list_of_two_elements( [1,1] ).
list_of-two_elements( [1,X] ). (on success, X here will have been unified with the integer 1.)