Your output, ceace
is printed by two different clauses.
First when your search reaches the base case, it prints ce
as it found edge(c, e)
:
path(X,Y) :- edge(X,Y),write(X),write(Y).
% i.e. path(c, e) :- edge(c, e), write(c), write(e).
Then your program returns to the recursive clause and prints ace
, which is your X
, Z
, and Y
:
path(X,Y) :- edge(X,Z),path(Z,Y),write(X),write(Z),write(Y).
% i.e. path(a, e) :- edge(a, c), path(c, e), write(a), write(c), write(e).
Your best option is to separate your search from the printing. Here I just add an argument to your search method to build the path.
path(X, Y, [X, Y]) :- edge(X, Y).
path(X, Y, [X|T]) :- edge(X, Z), path(Z, Y, T).
write_path(X, Y) :-
path(X, Y, Path),
maplist(write, Path).
This means you can print out any length of path and use that path data elsewhere, such as in finding the length of a path. As other solutions note, your search method will only work with finite tree structures.