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.
Related
I need to write prolog predicate that reads file and creates a list of words with repeating symbols. For example from text:
A dog and an apple and a pipe.
the result should be:
['apple', 'pipe']
I wrote this:
domains
file_ = f
s=string
c=char
i=integer
list=s*
list1=c*
predicates
str_a_list(s,list)
readfile(s,s)
example(s)
write_symbols(list1)
search(list1,list1,list1)
check(list)
str_list(s,list1)
search1(list1,c,i,i)
clauses
readfile(S,N):-existfile(N),!,
openread(F,N),
readdevice(F),file_str(N,S).
str_a_list("",_):-!.
str_a_list(" ",_):-!.
str_a_list(S,[H|T]):-fronttoken(S,H,S1),
str_a_list(S1,T).
search1([],_,I,I):-!.
search1([H|T],H,I,M):-I1=I+1,search1(T,H,I1,M).
search1([H|T],X,I,M):-H<>X,search1(T,X,I,M).
search([],_,_):-!.
search([H|T1],L,L0):-search1(L,H,0,M),M>=2,write_symbols(L0).
search([_|T],L,L0):-search(T,L,L0).
write_symbols([]):-write(" "),!.
write_symbols([H|T]):-write(H),write_symbols(T).
str_list("",[]).
str_list(S,[H|T]):- frontchar(S,H,S1),str_list(S1,T).
check([]):-!.
check([H|T]):-str_list(H,L),search(L,L,L),check(T).
example(Y):-readfile(S,Y),str_a_list(S,L),check(L).
goal
write("Enter file name: "),
readln(Y),example(Y).
It's giving me this error:
This flow pattern doesn't exist openread(o,i)
on line:
openread(F,N)
I tried computing this prolog task, maybe you may find something useful in my solution that may help you with yours. I've written my code using basic prolog:
First: The first predicate separates the sentence into words. I have used the built-in function split_string.Example: "The dog" will become "The","dog".
g(B):-
split_string(B,' ','', L),
d(L).
Second: In the second predicate, we split each word into a separate list of characters. Example: "dog" will become ["d","o","g"].
stringsplit(A,L1):-
atom_chars(A, L1).
Third: Then check each list if it contains doubles. the base case predicate tell to stop when get empty brackets. The checkdouble second predicate checks if a character is in the remaining list (using member). If yes then load the character in List R. Else, don't load the character in R.
checkdouble([],[]):-!.
checkdouble([H|T],[H|R]):-
member(H,T),
checkdouble(T,R).
checkdouble([],[]).
checkdouble([H|T],List):-
\+member(H,T),
checkdouble(T,List).
Fourth: By this point you will have a number of list: empty and those containing duplicates from each word. Example: For [bat] [apple] [polo] we will get [][p][o].
So now we use a predicate that simply prints the list of words that have doubles ignoring those words with no doubles i.e [].
s(_,B):-
B=[].
s(D,B):-
B\=[],
write(D).
Finally: Putting the code together:
g(B):-
split_string(B,' ','', L),
d(L).
d([]).
d([H|T]):-
stringsplit(H,K),
checkdouble(K,R),
s([H],R),
d(T).
s(_,B):-
B=[].
s(D,B):-
B\=[],
write(D).
checkdouble([],[]):-!.
checkdouble([H|T],[H|R]):-
member(H,T),
checkdouble(T,R).
checkdouble([],[]).
checkdouble([H|T],List):-
\+member(H,T),
checkdouble(T,List).
stringsplit(A,L1):-
atom_chars(A, L1).
Example:
?-g("A dog and an apple and a pipe").
OUTPUT:
[apple][pipe]
1true
false
?-g("Two funny little red apples fell from a tree one day").
OUTPUT:
[funny][little][apples][fell][tree]
1true
false
?-g("On a hill upon the grass there sits a squirrel in the chill").
OUTPUT:
[hill][grass][there][sits][squirrel][chill]
1true
false
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).
I have been working with Prolog since today, and wanted to create a simple test case. The basic idea was to have multiple sports defined, and it looks as follows:
soccer :- category(ball_sport),
check(has_11_players_per_team),
check(large_ball),
check(use_feet).
tennis :- category(ball_sport),
...
category(ball_sport) :-
check(has_a_ball).
Now I wanted to create a testcase, to see if both sports are of the ball_sport category, but have no idea to check these sports against eachother .. I thought it would be something like the code below, but it's obvious not. Is there an easy way to check these predicate categories? Thanks
both_ballsports(sport_one, sport_two) :-
has_category(sport_one, ball_sport),
has_category_sport_two, ball_sport).
It seems that first of all, you want to declaratively state attributes of a sport.
For example:
sport_attributes(soccer, [ball_sport,players(22),ball(large),use(feet)]).
sport_attributes(tennis, [ball_sport,players(2),players(4),ball(small),use(racket)]).
Note that I am relating sports to attributes. For comparison, the goals of the form check(X) you use above all seem to lack a critical argument, namely the actual sport for which they hold (or not). For example, the goal check(use_feet) either holds or not, but there is no means to qualify a unary predicate of this kind and state different facts for different sports.
Note the naming convention: We describe what each argument means, separated by underscores.
With this representation, both_ballsports/2 could look like this:
both_ballsports(Sport1, Sport2) :-
ballsport(Sport1),
ballsport(Sport2).
ballsport(Sport) :-
sport_attributes(Sport, As),
member(ball(_), As).
Sample query and answer:
?- both_ballsports(Sport1, Sport2).
Sport1 = Sport2, Sport2 = soccer ;
Sport1 = soccer,
Sport2 = tennis ;
Sport1 = tennis,
Sport2 = soccer ;
Sport1 = Sport2, Sport2 = tennis ;
false.
This can be used in all directions!
In prolog I'm trying to unify every valid pairing of needs with resources
needs([ece2090,1,m,13,16]).
needs([ece3520,1,tu,11,14]).
needs([ece4420,1,w,13,16]).
resources([joel, [ece2090,ece2010,ece3520,ece4420],[[m,13,16]]]).
resources([sam, [ece2010,ece4420],[]]).
resources([pete, [ece3520],[[w,13,16]]]).
using this formula
make_bid([Class,Sect,Day,Ts,Te],[Name,Cap,Unavail],[Class,Sect,Day,Ts,Te,Name,_]) :-
no_conflict_all_unavailable(Day,Ts,Te,Unavail),
course_capable(Class,Cap),
writef('%w %w %w\n',[Class,Sect,Name]),
fail.
and running this test.
test(Listing) :- needs(N), resources(R), make_bid(N,R,Listing).
The point of this part of the program is to pair every class with a teacher that both has the qualifications to teach the class and is not unavailable during that time. It's supposed to give a list.
?- test(Listing).
ece3520 1 joel
ece3520 1 pete
ece4420 1 joel
ece4420 1 sam
false.
When run, the above is generated. This is correct, but it's in a format that's useless to me, since I need it to be a variable of its own to do further computations. Then the solution is to use bagof or findall, right?
So I remove the fail clause from the main part of the program and then change the test to this
test(Bag) :- needs(N), resources(R), bagof(Listing,make_bid(N,R,Listing),Bag).
but it generates this
ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]]
If you look closely you'll see that there's no period at the end as well as a lack of a true/false statement. This would lead one to believe it is infinitely looping. This isn't the case however, as the Bag matrix is fully formed and I can simply type "." to end the program (instead of, you know, aborting it).
It only generates the first valid solution. Why is this happening?
You've structured your test predicate so that bagof/3 is called for every instance combination of needs(N) and resources(R) and so it collects each result of make_bid in it's own bagof/3 result:
ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]]
The first line is the write that is in make_bid predicate. The second line is the Bag result for the single query to make_bid for one pair of needs/resources. The last argument in the list, _G4310, occurs because your predicate uses _ and it's anonymous (never used/instantiated).
Your current make_bid is designed to write the results in a loop rather than instantiate them in multiple backtracks. So that could be changed to:
make_bid([Class, Sect, Day, Ts, Te], [Name, Cap, Unavail], [Class, Sect, Day, Ts, Te, Name, _]) :-
no_conflict_all_unavailable(Day, Ts, Te, Unavail),
course_capable(Class, Cap).
(NOTE: I'm not sure why you have _ at the end of the 3rd list argument. What does it represent?)
If you want to collect the whole result in one list, then you canb use findall/3:
findall([Class, Sect, Name], (needs(N), resources(R), make_bid(N, R, [Class, Sect, _, _, _, Name, _]), Listings).
This will collect a list of elements that look like, [Class, Sect, Name]. You could use bagof/3 here, but you'd need an existential quantifier for the variables in the make_bid/3 call that you don't want to bind.
If you wanted the entire Listing list, then:
findall(L, (needs(N), resources(R), make_bid(N, R, L)), Listings).
But each element of Listings will be a list whose last element is an anonymous variable, since that's how make_bid/3 is structured.
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.