Вместо попыток исправить способ вычисления длины пути в предикате travel
из опыта я знаю, что рефакторинг кода Пролога при обработке списка для вычисления другого свойства не сложен и обычно выполняется.
Таким образом, вместо этого рефакторируется предикат reverse/2
.Для рефакторинга reverse/2
нам сначала потребуется рабочий код для reverse/2
:
% Reverse using accumulator
rev(List,Rev) :-
rev(List,[],Rev) .
rev([],A,A).
rev([H|T],A,R) :-
rev(T,[H|A],R).
Примеры rev/2
?- rev([],L).
L = [].
?- rev([a],L).
L = [a].
?- rev([a,b],L).
L = [b, a].
?- rev([a,b,c],L).
L = [c, b, a].
Теперь для рефакторинга rev/2
для вычисления длины.
rev_n(List,Rev,N) :-
rev_n(List,[],Rev,N) .
rev_n([],A,A,0).
rev_n([H|T],A,R,N) :-
rev_n(T,[H|A],R,N0),
N is N0 + 1.
Примеры rev_n/2
?- rev_n([],L,N).
L = [],
N = 0.
?- rev_n([a],L,N).
L = [a],
N = 1.
?- rev_n([a,b],L,N).
L = [b, a],
N = 2.
?- rev_n([a,b,c],L,N).
L = [c, b, a],
N = 3.
Наконец, просто измените ваш код, чтобы использовать rev_n/2
, и удалите ненужные части кода, которые вычислили N.
path_2(Rel,A,B,Path,Len) :-
travel_2(Rel,A,B,[A],Q),
rev_n(Q,Path,Len).
travel_2(Rel,A,B,P,[B|P]) :-
call(Rel, A, B).
travel_2(Rel,A,B,Visited,Path) :-
call(Rel,A,C),
C \== B,
\+member(C,Visited),
travel_2(Rel,C,B,[C|Visited],Path).
Пример:
?- path_2(connected, 1, 5, Path, Length).
Path = [1, 2, 5],
Length = 3 ;
Path = [1, 2, 3, 5],
Length = 4 ;
Path = [1, 2, 3, 4, 5],
Length = 5 ;
Path = [1, 4, 5],
Length = 3 ;
Path = [1, 4, 3, 5],
Length = 4 ;
Path = [1, 4, 3, 2, 5],
Length = 5 ;
Path = [1, 3, 5],
Length = 3 ;
Path = [1, 3, 4, 5],
Length = 4 ;
Path = [1, 3, 2, 5],
Length = 4 ;
false.
Более практичным способом было бы просто использовать length/2
path_3(Rel,A,B,Path,Len) :-
travel_2(Rel,A,B,[A],Q),
reverse(Q,Path),
length(Path,Len).
?- path_3(connected, 1, 5, Path, Length).
Path = [1, 2, 5],
Length = 3 ;
Path = [1, 2, 3, 5],
Length = 4 ;
Path = [1, 2, 3, 4, 5],
Length = 5 ;
Path = [1, 4, 5],
Length = 3 ;
Path = [1, 4, 3, 5],
Length = 4 ;
Path = [1, 4, 3, 2, 5],
Length = 5 ;
Path = [1, 3, 5],
Length = 3 ;
Path = [1, 3, 4, 5],
Length = 4 ;
Path = [1, 3, 2, 5],
Length = 4 ;
false.