2015-08-17 2 views
3

Я новичок в Prolog, и я пытаюсь написать фрагмент кода, который вычисляет факториал числа. Этот код работает отлично:Код пролога вычисляющий факторный

fact(0,1). 
fact(N, R) :- N > 0, N1 is N - 1, fact(N1, R1), R is R1 * N. 

Но это один не делает:

fact(0, 1). 
fact(N, R) :- N > 0, fact(N - 1, R1), R is R1 * N. 

Может кто-то объяснить?

+0

Можно переписать вторую версию 'fact \ 2', чтобы каждый раз оценивать свой первый аргумент и обойти проблему во второй версии, но это более обычное, чтобы делать то, что у вас есть в первой версии (перед тем как пропустить оценку). Гибкость Prolog для управления «ленивой оценкой» аргументов потенциально полезна, но факториальное вычисление слишком просто, чтобы воспользоваться ею. – hardmath

+0

Задача состоит в том, чтобы переписать любую версию как хвостовую рекурсивную (подходящую для оптимизации последнего вызова). Часто для этого нужно ввести дополнительный аргумент (например, «факт/3»). – hardmath

ответ

4

Проблема заключается в том, что пролог в основном использует объединение делать вычисления. Чтобы заставить его выполнять арифметические операции, вам нужно сказать это, чтобы сделать это явно с помощью оператора 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]. - не обозначает вычитание - это часть структуры представляемого факта.

2

При прохождении арифметических выражений (вместо цифр) необходимо, чтобы оценивало выражения в определенное время.

Арифметические операторы, такие как (>)/2, автоматически делают это, поэтому цель 1 > (0+0) преуспевает, точно так же, как 1 > 0.

неявное объединение (в пункте главах) и явное объединение с (=)/2 целями выражают равенство произвольных терминов Пролога, а не только арифметических выражений. Таким образом, цель 0 = 0 преуспевает, но 0 = (1-1) терпит неудачу.

С арифметическим равенством (=:=)/2, 0 =:= 0 и 0 =:= (1-1) Успешно.

В своем втором определении fact/2 вы можете сделать первое предложение более общим, написав fact(N,1) :- N =:= 0. вместо fact(0,1).. В качестве дополнительного бонуса вы могли бы запускать запросы, такие как ?- fact(5+5,F). :)

Смежные вопросы