Using a list from a fact within Prolog rules

落花浮王杯 提交于 2019-12-20 05:38:29

问题


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 Lines 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!