在 Prolog 规则中使用来自事实的列表
Using a list from a fact within Prolog rules
我目前正在编写一个铁路线程序,但在使用来自事实的列表时遇到了一些麻烦。我对 Prolog 很陌生,到目前为止已经写了以下事实和规则:
location(euston, [northernLine]).
location(warrenStreet, [victoriaLine, northernLine]).
location(warwickAvenue, [bakerlooLine]).
location(paddington, [bakerlooLine]).
hasCommonLine(Location1, Location2, Line) :-
location(Location1, Line),
location(Location2, Line).
规则的想法是 return 两个位置共有的线路的名称。如果我尝试 hasCommonLine(warwickAvenue,paddington,Line).
这有效,但是如果我尝试 hasCommonLine(euston,warrenStreet,Line).
.
它 returns false
我怀疑这是因为该规则只检查列表的第一个元素,因此只比较 [northernLine]
和 [victoriaLine]
而不是检查列表中的每个元素。任何实现此目的的指导将不胜感激!
您的规则需要改进。
现在,它会检查这两个位置是否具有 完全相同的 行列表。
您应该做的是制定一个规则来检查两者之间是否存在重叠。您可以使用谓词来检查两个列表的交集。
看起来像这样:
hasCommonLine(Location1,Location2, CommonLines):-
location(Location1,Line1),
location(Location2,Line2),
intersection(Line1,Line2,CommonLines).
I suspect this is because the rule only checks the first element of the lists.
不,程序会检查两个列表是否相同。因此,只有当两个 Line
完全等价(相同的元素,相同的顺序)时它们才匹配。
不如un-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).
您可以检查 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].
我目前正在编写一个铁路线程序,但在使用来自事实的列表时遇到了一些麻烦。我对 Prolog 很陌生,到目前为止已经写了以下事实和规则:
location(euston, [northernLine]).
location(warrenStreet, [victoriaLine, northernLine]).
location(warwickAvenue, [bakerlooLine]).
location(paddington, [bakerlooLine]).
hasCommonLine(Location1, Location2, Line) :-
location(Location1, Line),
location(Location2, Line).
规则的想法是 return 两个位置共有的线路的名称。如果我尝试 hasCommonLine(warwickAvenue,paddington,Line).
这有效,但是如果我尝试 hasCommonLine(euston,warrenStreet,Line).
.
我怀疑这是因为该规则只检查列表的第一个元素,因此只比较 [northernLine]
和 [victoriaLine]
而不是检查列表中的每个元素。任何实现此目的的指导将不胜感激!
您的规则需要改进。
现在,它会检查这两个位置是否具有 完全相同的 行列表。
您应该做的是制定一个规则来检查两者之间是否存在重叠。您可以使用谓词来检查两个列表的交集。
看起来像这样:
hasCommonLine(Location1,Location2, CommonLines):-
location(Location1,Line1),
location(Location2,Line2),
intersection(Line1,Line2,CommonLines).
I suspect this is because the rule only checks the first element of the lists.
不,程序会检查两个列表是否相同。因此,只有当两个 Line
完全等价(相同的元素,相同的顺序)时它们才匹配。
不如un-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).
您可以检查 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].