Recursion prolog-检查结果后写出结果

Recursion prolog-检查结果后写出结果,recursion,printing,prolog,conditional-statements,graph-theory,Recursion,Printing,Prolog,Conditional Statements,Graph Theory,我一直在编写代码,以便我能够搜索图形中是否有路径,如果有路径,我希望打印出路径,如果有路径,我希望打印出所有路径。我有一个写路径的条件,如果谓词为true,但它从不打印,我应该怎么做 %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

我一直在编写代码,以便我能够搜索图形中是否有路径,如果有路径,我希望打印出路径,如果有路径,我希望打印出所有路径。我有一个写路径的条件,如果谓词为true,但它从不打印,我应该怎么做

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

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

allways(X,Y,[X,Y]) :-
   edge(X,Y).
allways(X,Y,[X|Nodes]) :-
   edge(X,B),
   allways(B,Y,Nodes).
如果
X
Y
之间有一条边,则它是路径的终点,并且两个节点都在列表中。否则,必须有一个中间节点
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
如果不希望出现这种行为,可以添加已访问节点的列表作为附加参数。我还建议使用更具描述性的名称,比如调用谓词的start\u dest\u path/3和实际关系的start\u dest\u path\u/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\u dest\u path/3使用空累加器调用start\u dest\u path\u/4。开始/结束路径中的目标映射列表(dif,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.
如果要排除此类解决方案,请将目标
映射列表(dif(D),Vs)
添加到start\u dest\u path\u/4的非递归规则中


请注意,谓词start\u dest\u path\u visitored/4仍然类似于原始帖子中的allways/2的结构,它有两个附加参数(路径和访问节点列表)和一个附加目标(maplist/2)。您可以在答案中看到一个稍微不同的加权路径定义。您可能还对中建议的更通用的定义和相应的答案感兴趣。

allways(p,Y)==true->writepath(X,Y)。
对于规则来说是无效的语法。您从何处想出
allways(p,Y)==true->writepath(X,Y)。
?您正在编写自己的序言语义这根本不像你想象的那样。Prolog谓词不是返回值的函数。试着把它写成
writepath(X,Y):-allways(u,Y)。
注意我把
\uu
而不是
P
,假设你真的不在乎
P
是什么。
?- start_dest_path(a,a,P).
P = [a, b, c, a] ;
P = [a, c, a] ;
false.