1

我目前正在编写一个铁路线程序,但在使用来自事实的列表时遇到了一些麻烦。我对 Prolog 很陌生,到目前为止,我已经写了以下事实和规则:

location(euston, [northernLine]).
location(warrenStreet, [victoriaLine, northernLine]).
location(warwickAvenue, [bakerlooLine]).
location(paddington, [bakerlooLine]).

hasCommonLine(Location1, Location2, Line) :-
    location(Location1, Line),
    location(Location2, Line).

这个想法是让规则返回两个位置共有的行的名称。如果我尝试,这会起作用hasCommonLine(warwickAvenue,paddington,Line).,但是如果我尝试,它会返回 false hasCommonLine(euston,warrenStreet,Line).

我怀疑这是因为该规则只检查列表的第一个元素,因此只比较[northernLine][victoriaLine]不是检查列表中的每个元素。任何指导来实现这一点将不胜感激!

4

3 回答 3

2

我怀疑这是因为该规则只检查列表的第一个元素。

不,程序会检查这两个列表是否相同。因此,只有当两个Lines 完全等价(相同元素,相同顺序)时,它们才会匹配。

使用列表指定行列表是相当非 Prolog的。通常他们将其表示为事实列表,例如:

location_new(euston,northernLine).
location_new(warrenStreet,victoriaLine).
location_new(warrenStreet,northernLine).
location_new(warwickAvenue,bakerlooLine).
location_new(paddington,bakerlooLine).

所以这里warrenStreet出现了两次:一次是victoriaLine,一次是northernLine。然后你可以简单地写:

hasCommonLine(Location1, Location2, Line) :-
    location_new(Location1, Line),
    location_new(Location2, Line).

尽管如此,由于情况并非如此,您可以编写一个辅助谓词location_helper/2

location_helper(A,B) :-
    location(A,L),
    member(B,L).

然后定义:

hasCommonLine(Location1, Location2, Line) :-
    location_helper(Location1, Line),
    location_helper(Location2, Line).
于 2017-01-17T13:53:16.323 回答
2

您可以检查是否Line是两个列表的成员:

 hasCommonLine(Location1, Location2, Line) :-
     location(Location1, Lines1),
     location(Location2, Lines2),
     member(Line, Lines1),
     member(Line, Lines2).

然后,如果您需要找到两个位置之间的所有公共线,您只需调用

 ?- findall(X, hasCommonLine(euston, warrenStreet, X), Y).
 Y = [northernLine].
于 2017-01-17T13:55:22.090 回答
1

你的规则需要改进。
现在,它检查两个位置是否具有完全相同的行列表。

你应该做的是制定一个规则来检查两者之间是否存在重叠。您可以使用谓词来检查两个列表的交集。

它看起来像这样:

hasCommonLine(Location1,Location2, CommonLines):-
    location(Location1,Line1),
    location(Location2,Line2),
    intersection(Line1,Line2,CommonLines).
于 2017-01-17T13:49:36.917 回答