Проблема в том, что вы никогда не говорили Прологу, что делать в случае D=0
.Таким образом, Пролог продолжает уменьшать значение D
до тех пор, пока D >= 1
больше не будет успешным, и это означает, что вы достигли точки " fail ".Затем Prolog начнет возврат, пока не найдет точку возврата, или здесь он размотает весь стек вызовов и сообщит об ошибке.
Даже если вам удастся реализовать условие остановки, это не достаточно, так как в вашем предикате вы используете [Ti|L]
в качестве параметра и рекурсивно вызываете с [Ti|L]
.Это означает, что рекурсивный вызов будет стремиться установить элемент в списке, тот же элемент (!), И если значения будут другими, это снова приведет к ошибке.
Поскольку вы построили список справа налево, вы можете использовать аккумулятор, который начинается с пустого списка и каждый раз добавляет элемент к списку в рекурсивном вызове.Условие останова затем объединяет аккумулятор с результатом.
t(R, L) :-
t(R, <b>[]</b>, L).
t(0, <b>R</b>, <b>R</b>).
t(D, <b>L</b>, <b>R</b>) :-
D >= 1, !,
Ti is D * ((D + 1) / 2),
D1 is D - 1,
t(D1, <b>[Ti|L]</b>, <b>R</b>).
Это затем дает ожидаемое:
?- t(2, L).
L = [1, 3.0] ;
false.
Обратите внимание, что вы можете сделать вышеупомянутое более эффективным, работая влево-направо, и используйте аккумулятор, который суммирует индексы.
Например:
t(N, R) :-
t(1, 1, N, R).
t(I, _, N, []) :-
I > N.
t(I, A, N, [A|T]) :-
I =< N,
I1 is I+1,
A1 is A + I1,
t(I1, A1, N, T).