How to create predicate that is true if gets different values - prolog

I would like to ask how to create predicate that returns true if gets different values.
I have this database:
fruit(apple).
fruit(peach).
fruit(banana).
fruit(orange).
fruit(mandarine).
fruit(plum).
I need predicate threeFruits/3 that takes three fruits and says if they are different i.e.
threeFruits(apple,peach,banana). -> true
threeFruits(apple,apple,banana). -> false .. etc.
The code I have so far is not correct:
threeFruits(X,Y,Z):- fruit(X),fruit(Y),fruit(Z).
I tried also unification, but it can tell me only if they are same, but not working for different.
threeFruits(fruit(X),fruit(X),fruit(X)).
Thank you in advance for any hint.

Assuming the X, Y, Z are really atoms for which fruit/1 is valid, you can test whether they pairwise "do not unify" by using the negation of =/2 (i.e. the negation of unification)
threeFruits(X,Y,Z) :-
assertion(fruit(X)),
assertion(fruit(Y)),
assertion(fruit(Z)),
X\=Y,Y\=Z,X\=Z.
Alternatively, you can use the negation of ==/2 to check whether they pairwise "are not the same":
threeFruits(X,Y,Z) :-
assertion(fruit(X)),
assertion(fruit(Y)),
assertion(fruit(Z)),
X\==Y,Y\==Z,X\==Z.

Related

Prolog: Assign value to Variable in Predicate

With the following rules:
test('John', ebola).
test('John', covid).
test('Maria', covid).
How can I create a predicate that would tell me if John or Maria took (both) the Ebola and Covid tests?
I want to do something similar to this (I know it's wrong, just the idea):
tests(Persona, Ebola, Covid) :-
Ebola = test(Persona, ebola),
Covid = test(Persona, covid).
Prolog is relational not functional. test(X, Y) either holds or fails and doesn't return a value like what you thought. Here's what you should have written:
tests(Persona) :-
test(Persona, ebola),
test(Persona, covid).
You can query tests('John') which is true since both test/2 calls succeeds. The query tests('Maria') fails because test('Maria', ebola) fails.
Does it answer your question ?

Learn Prolog now: Why answering true to the first query of exercise 1.5?

I have just started learning Prolog, and I'm wondering about the first question of this exercise.
%% Suppose we are working with the following knowledge base:
wizard(ron).
hasWand(harry).
quidditchPlayer(harry).
wizard(X) :- hasBroom(X), hasWand(X).
hasBroom(X) :- quidditchPlayer(X).
How does Prolog respond to the following queries?
wizard(ron). -> true
witch(ron). -> undefined procedure
wizard(hermione). -> false
witch(hermione). -> undefined procedure
wizard(harry). -> true
wizard(Y). -> Y = ron ; Y = harry.
witch(Y). -> undefined procedure
Using swipl on Ubuntu, importing the knowledge base for this exercise, first of course trying to decipher what Prolog will returns, and finally checking by myself.
Ok pretty boring stuff until now, I have seen a few answer to these exercises over Github (here, here and there), and I don't understand the answer to the first one: %% 1. wizard(ron). -> true.
First of all the interpreter is complaining about the two definition of what is a wizard:
Warning: /tmp/prolog/ex15.pl:4:
Clauses of wizard/1 are not together in the source-file
Earlier definition at /tmp/prolog/ex15.pl:1
Current predicate: quidditchPlayer/1
Use :- discontiguous wizard/1. to suppress this message
Secondly, when querying I obtain:
?- wizard(ron).
true ;
false.
The way I get it, first Prolog returns the first fact from the knowledge base, then apply the rule head and find out that ron has neither a broom nor a wand.
All this leading to my question: what subtlety have I missed that makes others writing true as an answer to this query?
what subtlety have I missed that makes others writing true as an answer to this query?
`?- wizard(ron).`
true;
false
You have the clause (fact) wizard(ron). in your KB.
To make the things clearer you can write the fact also as the rule clause:
wizard(ron) :- true.
As you can see this is pretty redundant notation but useful in some cases as the general fact representation.
So your query can be interpreted as follows:
Is there an wizard called ron?
Since you have the fact wizard(ron) :- true.
Prolog will first unify the goal and the head.
In your case unify is trivial comparison because no variables are in the goal and the head.
Then Prolog tries to prove body. The body is builtin predicate true, so you quickly get the answer - true.
Then pressing ';' you initiate the search for the alternative solution.
Since no (more) solutions exist for the query wizard(ron), Prolog writes false.
The dot operator designates the clause end. So you wrongly typed dots in your examples:
-> operator means if-then-else relation. It can be used within clause body.
For example you can write std_member/2 as if_member/2
std_member(X, [ X | _ ]).
std_member(X, [ _ | Xs ]) :-
std_member(X, [ _ | Xs).
if_member(X, [ Y | Xs ]) :-
X = Y -> true;
if_member( X, Xs ).

use operator as constructor in prolog

I'm writing a function called leagalCourse, it takes just one parameter, a course list. A course like, for example, john+mary+94 would represent a project done by John and Mary with a mark of 94.
It should be true if the course data is “legal”, which means that it must not have a project with the same name twice such as john+john+70.
There also must not be two projects in the list containing the same pair of students. So if there’s a project harry+ron+82 in the list, it would be illegal for the list also to contain harry+ron+90 or ron+harry+63.
There is a sample output:
?- legalCourse([one+two+3,four+five+6,one+six+7]).
true.
?- legalCourse([one+two+3,four+four+6,one+six+7]).
false.
?- legalCourse([one+two+3,four+five+6,one+two+7]).
false.
?- legalCourse([one+two+3,two+one+6,one+six+7]).
false.
This is what I tried:
legalCourse([]).
legalCourse(X) :-
diffName(X).
legalCourse([Project|M]):-
diffName(Project),
not(samePair([Project|M])),
legalCourse(M).
diffName(Name1+Name2+_) :-
Name1 \= Name2.
/*can not have duplicated group*/
samePair([Name1+Name2+_|More]) :-
append([[head],tail,More]),
member(Name1,[head]),
member(Name2,[head]).
The function partially worked before I added the samePair predicate.
I think this works, you need to switch the vars and check both are different in check_no_dups/1.
legalCourse(List):-
maplist(triple_double,List,ListDouble),
check_no_dups(ListDouble).
check_no_dups([]).
check_no_dups([H|T]):-
H =X+Y,
maplist(dif(H),T),
H2 =Y+X,
maplist(dif(H2),T),
check_no_dups(T).
triple_double(X+Y+_Z,X+Y):-dif(X,Y).

Writing a predicate to add atoms

I have to write a predicate to do work like following:
?- cat(north,south,X).
X = northsouth
?- cat(alley,'91',Y).
X = alley91
?-cat(7,uthah,H).
Bad Input
H = H
Please Help..
atom_concat_redefined(A1, A2, A3) :-
( nonvar(A1) -> atom_chars(A1, Chs1) ; true ),
( nonvar(A2) -> atom_chars(A2, Chs2) ; true ),
( nonvar(A1), nonvar(A2) -> true ; atom_chars(A3, Chs3) ),
append(Chs1, Chs2, Chs3),
atom_chars(A1, Chs1),
atom_chars(A2, Chs2),
atom_chars(A3, Chs3).
This definition produces the same errors in a standard conforming implementation like SICStus or GNU - there should be no other differences, apart from performance. To compare the errors use the goal:
?- catch(atom_concat_redefined(A,B,abc+1), error(E,_), true).
E = type_error(atom,abc+1).
Note the underscore in error(E,_), which hides the implementation defined differences. Implementations provide additional information in this argument, in particular, they would reveal that atom_chars/2 or atom_concat/3 produced the error.
atom_codes/2 it's the ISO approved predicate to convert between an atom and a list of codes. When you have 2 lists corresponding to first two arguments, append/3 (alas, not ISO approved, but AFAIK available in every Prolog), will get the list corresponding to third argument, then, convert that list to atom...
Note that, while append/3 is a 'pure' Prolog predicate, and can work with any instantiation pattern, atom_codes/2 requires at least one of it's argument instantiated. Here is a SWI-Prolog implementation of cat/3, 'working' a bit more generally. I hope it will inspire you to read more about Prolog...
ac(X,Xs) :- when((ground(X);ground(Xs)), atom_codes(X,Xs)).
cat(X,Y,Z) :- maplist(ac, [X,Y,Z],[Xs,Ys,Zs]), append(Xs,Ys,Zs).
edit
as noted by #false I was wrong about append/3. Now I'll try to understand better what append/3 does... wow, a so simple predicate, so behaviour rich!

Prolog, how to show multiple output in write()

go :- match(Mn,Fn),
write('--Matching Result--'),
nl,
write(Mn),
write(' match with '),
write(Fn),
match(Mn1,Fn1).
person(may,female,25,blue).
person(rose,female,20,blue).
person(hock,male,30,blue).
person(ali,male,24,blue).
match(Mn,Fn):-person(Fn,'female',Fage,Fatt),
person(Mn,'male',Mage,Matt),
Mage>=Fage,
Fatt=Matt.
Hi,this is my code...but it's only can show the 1 output...but there are 3 pair of matching in match(X,Y).how to show them all in my go function.
Thank you
You get all your matches if you force backtracking, usually by entering ; (e.g. in SWI Prolog). But you also see that you are getting unnecessary outputs true. This is because the last clause in go is match(Mn1,Fn1). This clause succeeds three times and binds the variables Mn1,Fn1 but then only true is output, because you do not write() after that clause. The fourth time match(Mn1,Fn1) fails and by backtracking you come back to the first clause match(Mn,Fn) that matches, the match is output, etc.
You surely do not want to have this behavior. You should remove the last clause match(Mn1,Fn1) in go. Now by pressing ; you get the 3 matches without any output true in between.
But what you likely want is that the program does the backtracking. To achieve this, you just need to force backtracking by adding false as the last clause. To get proper formatting of the output, use the following program. The last clause go2. is added to get true at the very end.
go2 :- write('--Matching Result--'), nl,
match(Mn,Fn),
write(Mn), write(' match with '), write(Fn), nl,
fail.
go2.
This technique is called failure driven loop.
If you have any predicate that has multiple results and want to to find all of them, you should use findall/3
For example, in your case, you could do something like:
findall([X,Y], match(X,Y),L).
L will be a list that will contain all the X,Y that satisfy match(X,Y) in the format [X,Y].
for example, assuming that:
match(m1,f1).
match(m2,f2).
the result will be L = [ [m1,f1], [m2,f2] ]
note that you can define the format as you wish, for example you could write:
findall(pair(X,Y), match(X,Y), L).
L = [ pair(m1,f1), pair(m2,f2) ]
findall( X, match(X,Y), L).
L = [ m1, m2]
findall( 42, match(X,Y), L).
L = [42, 42]
then you have to recurse on the list to print them.
However, if you wish to find one result, run some code and then continue you could use forall/2:
forall(match(X,Y), my_print(X,Y).
Prolog is a lazy language. Which means that it will stop once it has found a condition that made your problem true. This will be the very first match alone.
IF your code is working (I haven't tried it), then you should try and run the match-statement like this in your prolog inspector: match(X,Y)
The prolog inspector will return all states and print them for you.

Resources