问题
I am currently writing a rail line program but am having a little trouble using lists that come from facts. I am quite new to Prolog and so far have written the following facts and rules:
location(euston, [northernLine]).
location(warrenStreet, [victoriaLine, northernLine]).
location(warwickAvenue, [bakerlooLine]).
location(paddington, [bakerlooLine]).
hasCommonLine(Location1, Location2, Line) :-
location(Location1, Line),
location(Location2, Line).
The idea is for the rule to return the name of the line(s) that the two locations have in common. This works if I try hasCommonLine(warwickAvenue,paddington,Line).
, however it returns false if I try hasCommonLine(euston,warrenStreet,Line).
.
I suspect this is because the rule only checks the first element of the lists, therefore only compares [northernLine]
and [victoriaLine]
rather than checking every element in the list. Any guidance to accomplish this would be much appreciated!
回答1:
You can check if Line
is a member of both lists:
hasCommonLine(Location1, Location2, Line) :-
location(Location1, Lines1),
location(Location2, Lines2),
member(Line, Lines1),
member(Line, Lines2).
Then, if you need to find all the lines common between two locations, you would simply call
?- findall(X, hasCommonLine(euston, warrenStreet, X), Y).
Y = [northernLine].
回答2:
I suspect this is because the rule only checks the first element of the lists.
No, the program checks if the two lists are identical. So only if both Line
s are completely equivalent (same elements, same order) they match.
It is rather un-Prolog to specify the list of lines using a list. Usually they represent it as a list of facts like:
location_new(euston,northernLine).
location_new(warrenStreet,victoriaLine).
location_new(warrenStreet,northernLine).
location_new(warwickAvenue,bakerlooLine).
location_new(paddington,bakerlooLine).
So here warrenStreet
occurs twice: once with the victoriaLine
and once with the northernLine
. Then you could simply write:
hasCommonLine(Location1, Location2, Line) :-
location_new(Location1, Line),
location_new(Location2, Line).
Nevertheless since this is not the case, you could write a helper predicate location_helper/2
:
location_helper(A,B) :-
location(A,L),
member(B,L).
and then define:
hasCommonLine(Location1, Location2, Line) :-
location_helper(Location1, Line),
location_helper(Location2, Line).
回答3:
Your rule needs improvement.
Right now, it checks if the two locations have exactly the same list of lines.
What you should do, is make a rule that checks if there is overlap between the two. You could use a predicate that checks the intersection of the two lists.
It would look something like this:
hasCommonLine(Location1,Location2, CommonLines):-
location(Location1,Line1),
location(Location2,Line2),
intersection(Line1,Line2,CommonLines).
来源:https://stackoverflow.com/questions/41698790/using-a-list-from-a-fact-within-prolog-rules