Проблема заключается в том, что пролог в основном использует объединение делать вычисления. Чтобы заставить его выполнять арифметические операции, вам нужно сказать это, чтобы сделать это явно с помощью оператора is
.
Итак, в вашей первой программе вы явно говорите ей, чтобы выполнить вычитание с помощью пункта N1 is N - 1
, чтобы работала так, как ожидалось.
Но в вашей второй программе вы не запрашиваете арифметические вычисления, а унификацию, когда вы написали fact(N - 1, R1)
.
Если бы я имел тот факт fact(5 - 1, foo).
определен, то я мог бы запросить ?- fact(N - 1, Y), write([N, Y]).
и пролог бы с удовольствием унифицировать N
с 5
и Y
с foo
. Этот запрос будет выводить [5, foo]
.
Итак, чтобы сделать еще один шаг, если бы у меня был факт fact(foo - bar).
, тогда запрос ?- fact(X - Y), write([X, Y]).
был бы счастливо унифицирован и возвращен [foo, bar]
. -
не обозначает вычитание - это часть структуры представляемого факта.
Можно переписать вторую версию 'fact \ 2', чтобы каждый раз оценивать свой первый аргумент и обойти проблему во второй версии, но это более обычное, чтобы делать то, что у вас есть в первой версии (перед тем как пропустить оценку). Гибкость Prolog для управления «ленивой оценкой» аргументов потенциально полезна, но факториальное вычисление слишком просто, чтобы воспользоваться ею. – hardmath
Задача состоит в том, чтобы переписать любую версию как хвостовую рекурсивную (подходящую для оптимизации последнего вызова). Часто для этого нужно ввести дополнительный аргумент (например, «факт/3»). – hardmath