Prolog setOf with Multiple Predicates - prolog

In my prolog database, I have below facts:
played('Sharon rose', piano).
played('Robert Kay', piano).
played('Kelvin Cage', drums).
singer('Robert Kay').
band_leader('Sharon rose').
I want to print out all the names uniquely as a single list.
Below is my query using setof and the output:
setof(X, (played(X,_);singer(X);band_leader(X)), Output).
Output = ['Robert Kay','Sharon rose'] ? ;
Output = ['Kelvin Cage'] ? ;
Output = ['Robert Kay','Sharon rose']
yes
However, the output isn't what I want.
I want it to print out the names uniquely as a list.

You get multiple answers due to the anonymous variable in the goal argument of setof/3. Try instead:
?- setof(X, Y^(played(X,Y);singer(X);band_leader(X)), Output).

Related

Prolog, print employees with same names

This is my first time using Prolog.
I have employees:
employee(eID,firstname,lastname,month,year).
I have units:
unit(uID,type,eId).
I want to make a predicate
double_name(X).
that prints the last names of the employees with the same first name in the unit X.
I am doing something like this :
double_name(X) :-
unit(X,_,_eID),
employee(_eID,_firstname,_,_,_),
_name = _firstname,
employee(_,_name,_lastname,_,_),
write(_lastname).
But it prints all the employees in the unit.
How can i print only the employees with the same name ?
unit(unit_01,type,1).
unit(unit_01,type,2).
unit(unit_01,type,3).
employee(1,mary,smith,6,1992).
employee(2,fred,jones,1,1990).
employee(3,mary,cobbler,2,1995).
double_name(Unit) :-
unit(Unit,_,Eid_1),
employee(Eid_1,Firstname,Lastname_1,_,_),
unit(Unit,_,Eid_2),
Eid_1 \= Eid_2,
employee(Eid_2,Firstname,Lastname_2,_,_),
write(Firstname),write(","),write(Lastname_1),nl,
write(Firstname),write(","),write(Lastname_2).
Variables in Prolog typically start with an upper case letter, but starting them with and underscore is allowed, but not typical.
In double_name/2 the predicates like
unit(Unit,_,Eid_1)
employee(Eid_1,Firstname,Lastname_1,_,_)
are used to load the values from the facts into variables while pattern matching (via unification) that the bound variables match with the fact.
To ensure that a person is not compared with themselves.
Eid_1 \= Eid_2
and to make sure that two people have the same first name the same variable is used: Firstname.
The write/1 and nl/0 predicates just write the result to the screen.
Example:
?- double_name(unit_01).
mary,smith
mary,cobbler
true ;
mary,cobbler
mary,smith
true ;
false.
Notice that the correct answer is duplicated. This can be resolved.
See: Prolog check if first element in lists are not equal and second item in list is equal
and look at the use of normalize/4 and setof/3 in my answer
which I leave as an exercise for you.

Can I subtitude functor with variable in a predicate

I am new to prolog, and using BProlog.
I have been reading some example program to execute query on group of related data. But in order to infer from facts with similar structure, they wrote many predicates like search_by_name,search_by_point, which are partly duplicated.
% working search in example
search_by_name(Key,Value) :-
Key == name,
sname(ID,Value),
point(ID,Point),
write(Value),write(Point),nl.
And when I try to replace them with a more general version like this:
% a more general search I want to write
% but not accepted by BProlog
search_by_attr(Key,Value) :-
Key(ID,Value),
sname(ID,Name),
point(ID,Point),
write(Name),write(Point),nl.
error arised:
| ?- consult('students.pl')
consulting::students.pl
** Syntax error (students.pl, 17-21)
search_by_attr(Key,Value) :-
Key<<HERE>>(ID,Value),
sname(ID,Name),
point(ID,Point),
write(Name),write(Point),nl.
1 error(s)
Am I doing it the wrong way, or is such subtitution impossible in prolog?
code and example data can be found at https://gist.github.com/2426119
I don't know any Prolog that accept variables functors.
There is call/N, or univ+call/1.
search_by_attr(Key,Value) :-
call(Key, ID, Value), % Key(ID,Value)
...
or
search_by_attr(Key,Value) :-
C =.. [Key, ID, Value], % univ
call(C), % Key(ID,Value)
...

translate(list1, list2) in prolog

I was trying a functor translate([3,5,1,3],[three,five,one,three]) which does the operation of printing numbers. I get a strange warning while executing like this,
35 ?- translate([1,2,3],[a,b,c]).
ERROR: write/2: stream `a' does not exist
domains
list1=integer*
list2=symbol*
predicates
translate(list1,list2)
means(integer,symbol)
clauses
translate([],[]).
translate([],_):-
write("\nError in Input").
translate(_,[]):-
write("\nError in Input").
translate([Head1|Tail1],[Head2|Tail2]):-
write(Head2," = "),
means(Head1,Name),
write(Name,"\n"),
translate(Tail1,Tail2).
means(0,zero).
means(1,one).
means(2,two).
means(3,three).
means(4,four).
means(5,five).
means(6,six).
means(7,seven).
means(8,eight).
means(9,nine).
What exactly is the problem? This is the expected value.
translate([1,2,3],[a,b,c])
a = one
b = two
c = three
Yes
Variables need to be uppercase:
translate([1,2,3],[A,B,C]).
When you enter the translate([Head1|Tail1],[Head2|Tail2]) clause, a unifies with Head2, and then you try to satisfy write(Head2, "="), which is write(a, "=").
write/2 takes as first argument a Stream and writes the second argument to that Stream.
Presumably you want to use - if you want output at all - something like
writef('Head2 = %w', [Head2])
(I got the formatting from here.)

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.

Putting all results of a query in a list in Prolog

I'd like to know how to make a predicate that puts all results obtained from some query (so I get a result and press semicolon until I get False) in a list.
For example if I write foo(X,[1,2,3]). in some Prolog listener, let's say the result is
X=[11];
X=[22];
False.
I would like to get all those results in a list, so something like the following would happen.
?-another_foo(X,[1,2,3]).
X=[[11],[22]].
another_foo would somehow use foo to create a list with all the results from foo.
I just don't know how.
Use the built-in predicate findall/3:
?-findall(X0, foo(X0, [1,2,3]), X).
X = [[11], [22]].
You can define your another_foo/2:
another_foo(X, Input) :-
findall(X0, foo(X0, Input), X).

Resources