我知道Prolog在技术上没有“回归”,但我不知道如何制定这个问题。
我找到了一些用于在地铁站之间寻找路线的算法示例代码。它运作良好,但它应该只打印结果,因此很难扩展或例如findall/3
。
% direct routes
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Y,Stations),
append(Output,[[X,Line,Y]],NewOutput),
print(NewOutput).
% needs intermediate stop
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Intermediate,Stations),
X\=Intermediate,Intermediate\=Y,
append(Output,[[X,Line,Intermediate]],NewOutput),
findRoute(Intermediate,Y,[Line|Lines],NewOutput).
line
是一个带有原子的谓词和包含这些站的列表
例如:line(s1, [first_stop, second_stop, third_stop])
所以我要做的就是在第11行摆脱print
并在我的规则中添加一个额外的变量来存储结果供以后使用。但是我失败了,因为无论我尝试什么,它都会进入无限循环或返回false。
现在:
?- findRoute(first_stop, third_stop, [], []).
% prints [[first_stop,s1,third_stop]]
想要:
?- findRoute(first_stop, third_stop, [], R).
% [[first_stop,s1,third_stop]] is stored in R
答案 0 :(得分:3)
和你一样,我也经常在Prolog初学者中看到这种模式,特别是如果他们使用坏书和其他材料:
solve :-
.... some goals ...
compute(A),
write(A).
由于以下原因,上述几乎每一行都存在问题:
write/1
是副作用,其输出仅在系统终端上可用。这使我们没有简单的方法来实际测试谓词。这些模式应该总是看起来像:
solution(S) :-
condition1(...),
condition2(...),
condition_n(S).
其中condition1
等只是纯粹的目标,描述了S
是解决方案的意义。
查询时
?- solution(S).
然后S
的绑定将自动打印在顶层。让toplevel为你做印刷!
在您的情况下,有一个直接的解决方法:简单地使NewOutput
其中一个参数,并删除最终的副作用:
route(X, Y, Lines, Output, NewOutput) :- line(Line, Stations), \+ member(Line, Lines), member(X, Stations), member(Y, Stations), append(Output, [[X,Line,Y]], NewOutput).
另请注意,我已将名称更改为route/5
,因为如果参数已全部已实例化,则谓词也是,这对于测试等非常有用。
此外,在描述列表时,使用dcg表示法通常会从中受益匪浅。
代码看起来与此类似:
route(S, S, _) --> []. % case 1: already there route(S0, S, Lines) --> % case 2: needs intermediate stop { line_stations(Line, Stations0), maplist(dif(Line), Lines), select(S0, Stations0, Stations), member(S1, Stations) }, [link(S0,Line,S1)], route(S1, S, [Line|Lines]).
方便的是,您可以使用它来描述列表的串联,而不需要append/3
这么多。我还做了一些其他的改进,以提高纯度和可读性,我将确切的差异作为一个简单的练习。
您可以使用DCG接口谓词phrase/2
来调用它,使用:
?- phrase(route(X,Y,[]), Rs).
其中Rs
是找到的路线。另请注意,我使用link/3
形式的术语来表示路线的链接。当知道arity时,使用专用术语是一种好习惯。如果您事先不知道需要表示多少元素,列表就是好的。