Почему это работает:
power(_,0,1) :- !. power(X,Y,Z) :- Y1 is Y - 1, power(X,Y1,Z1), Z is X * Z1.
И это дает исключение переполнения стека?
power(_,0,1) :- !. power(X,Y,Z) :- power(X,Y - 1,Z1), Z is X * Z1.
Поскольку арифметические операции выполняются только над предложениями через оператор is. В первом примере Y1 привязан к результату вычисления Y - 1. В последующем система пытается доказать силу предложения (X, Y - 1, Z1), которая объединяется с мощностью (X ', Y', Z ') связывание X' = X, Y '= Y - 1, Z' = Z. Это затем повторяется снова, поэтому Y '' = Y - 1 - 1 и т. Д. Для бесконечности, фактически не выполняя вычисления.
is
Пролог - это, прежде всего, просто унификация терминов - вычисление в «общем» смысле должно быть запрошено явно.
Оба определения не работают должным образом.
Рассмотрим
?- pow(1, 1, 2).
, который повторяется для обоих определений, поскольку второе предложение может применяться независимо от второго аргумента. Разрез в первом предложении не может отменить это. Второму пункту нужна цель Y > 0 перед рекурсивной целью. Использование (is)/2 все еще является хорошей идеей для получения реальных решений.
Y > 0
(is)/2
Лучше всего (для начинающих) начинать с арифметики-преемника или clpfd и вообще избегать вырезания пролога .
См. Например: Предикат Пролога - бесконечный цикл