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.