prolog - 检查结果后写出结果

时间:2017-10-03 11:11:12

标签: recursion graph printing prolog conditional-statements

我一直在编写代码,以便我能够搜索图表中是否有路径,如果有的话我想打印出路径,如果有的话我想打印出所有这些。我有条件写道路如果谓词是真的但它永远不打印,我该怎么办?

%graph
edge(a,b).
edge(a,c).
edge(b,c).
edge(c,d).
edge(c,e).
edge(d,e).
edge(f,g).
edge(g,h).


% condition

allways(X,Y) :-
edge(X,Y).


% recursion
allways(X,Y) :-
edge(X,B),
allways(B,Y).



%print out path if there is one (its meant to print out all paths it can find)
allways(P,Y) == true -> writepath(X,Y).

writepath(X,Y):-
edge(X,Y).

writepath(X,Y) :-
edge(X,B),
write(B),
writepath(B,Y).

1 个答案:

答案 0 :(得分:3)

您是否考虑过添加列表作为第三个参数来收集路径上的节点?不是使用write / 1来输出每个节点,而是为每个解决方案提供一个包含从开始到目标的所有节点的列表。请考虑对您的代码进行以下更改:

allways(X,Y,[X,Y]) :-
   edge(X,Y).
allways(X,Y,[X|Nodes]) :-
   edge(X,B),
   allways(B,Y,Nodes).

如果XY之间存在边缘,则它是路径的末尾,并且两个节点都在列表中。否则,必须有一个中间节点B,并且列表中只有X。这个谓词产生了预期的结果:

?- allways(a,e,P).
P = [a, b, c, e] ;
P = [a, b, c, d, e] ;
P = [a, c, e] ;
P = [a, c, d, e] ;
false.

现在,您将获得从开始到目标的每条路径的节点列表。但是,此查询仅终止,因为您提供的图形是非循环的。考虑添加边缘,使图形包含一个循环:

edge(a,b).
edge(a,c).
edge(b,c).
edge(c,e).
edge(c,d).
edge(d,e).
edge(f,g).
edge(g,h).
edge(c,a). % <- new edge

现在上面的查询由于新添加的循环而循环:

?- allways(a,e,P).
P = [a, b, c, e] ;
P = [a, b, c, d, e] ;
P = [a, b, c, a, b, c, e] ;
P = [a, b, c, a, b, c, d, e] ;
P = [a, b, c, a, b, c, a, b, c, e] ;
P = [a, b, c, a, b, c, a, b, c, d, e] ;
P = [a, b, c, a, b, c, a, b, c, a, b, c, e] ;
.
.
.

如果您不想要此行为,可以添加一个已访问节点列表作为附加参数。我还建议一个更具描述性的名称,比如调用谓词的start_dest_path / 3和实际关系的start_dest_path_visited / 4:

:- use_module(library(apply)).

start_dest_path(S,D,P) :-
   start_dest_path_visited(S,D,P,[]).

start_dest_path_visited(S,D,[S,D],Vs) :-
   maplist(dif(S),Vs),
   edge(S,D).
start_dest_path_visited(S,D,[S|Nodes],Vs) :-
   maplist(dif(S),Vs),
   edge(S,X),
   start_dest_path_visited(X,D,Nodes,[S|Vs]).

谓词start_dest_path / 3使用空累加器调用start_dest_path_visited / 4。 start_dest_path_visited / 4中的目标maplist(dif(S),Vs)确保尚未访问节点S。现在查询也以循环终止:

?- start_dest_path(a,e,P).
P = [a, b, c, e] ;
P = [a, b, c, d, e] ;
P = [a, c, e] ;
P = [a, c, d, e] ;
false.

虽然路径不能包含循环,但此定义允许路径为一个大循环。请考虑以下查询:

?- start_dest_path(a,a,P).
P = [a, b, c, a] ;
P = [a, c, a] ;
false.

如果要排除此类解决方案,请将目标maplist(dif(D),Vs)添加到start_dest_path_visited / 4的非递归规则中。

注意谓词start_dest_path_visited / 4仍然类似于原始帖子中的allways / 2结构,带有两个附加参数(路径和访问节点列表)和一个额外目标(maplist / 2)。您可以在thisthis答案中看到加权路径的略有不同的定义。您可能还对this question中建议的更通用的定义以及相应的答案感兴趣。