1

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!

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555

3 Answers3

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).
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
2

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].
VHarisop
  • 2,816
  • 1
  • 14
  • 28
1

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).