2017-02-21 28 views
2

У меня есть факторный предикат fact(N,F), где либо N, либо F или оба ограничены рядом.Prolog factorial predicate

Например, у меня есть fact(3,F) или fact(N,6). Вот мой предикат, который работает, но я действительно не понимаю, как это сделать. Я использовал trace, но все еще есть проблемы с пониманием этого.

fact(0,1). 
fact(N,F) :- 
     fact(N1,F1), 
     N is N1 + 1, 
     F is N * F1. 
+1

Вы также можете вручную «пройти» через него: 'fact (3, F)' не соответствует 'fact (0, 1)' (поскольку 3 и 0 не являются унифицируемыми), поэтому Prolog будет соответствовать следующему пункту 'fact (N, F)' с 'N = 3'. Затем он вызывает «факт (N1, F1)», который снова появляется с «N1 = 0» и «F1 = 1» для первого предложения, и так далее. Обратите внимание: после нахождения решения он пытается найти больше и не заканчивается, вызывая переполнение стека. – lurker

+1

Мне любопытно: как вы начали писать этот предикат, если не знаете, как это работает? – lurker

+1

@lurker: Это очень понятно: другая версия, возможно, вызвала ошибку создания. – false

ответ

4

Вы можете попытаться пройти через свою программу шаг за шагом, чтобы понять, что происходит. Вы будете очень медленными и очень ненадежными. Или, вместо этого, Prolog делает (часть) работу. Поэтому идея состоит в том, чтобы немного изменить программу, а затем посмотреть, что пролог думает об этом.

Это то, что я вижу, когда я смотрю на вашу программу - это называется

fact(0,1) :- false. 
fact(N,F) :- 
     fact(N1,F1), false, 
     N is N1 + 1, 
     F is N * F1.

Когда этот фрагмент прекращается? Посмотрите на оставшуюся видимую часть! N встречается только один раз в голове: никто не интересуется первым аргументом! То же самое для F. Поэтому: Независимо от того, какие аргументы у вас есть, программа не будет завершена. И, таким образом, то же самое относится к вашей оригинальной программе!

В оригинальной версии это было не так ясно. Берегитесь:

?- fact(29,F). 
F = 8841761993739701954543616000000 

На первый взгляд это выглядит красиво, но если вы спросите на следующий ответ (с пробелами или ;), вы закончите в цикле. Хуже того, ложные запросы в настоящее время цикл сразу:

?- fact(29,1). 
** LOOPS ** 

Итак, как вы можете найти эти проблемы, не понимая, что именно происходит? Это то, что false для. Цель, которая никогда не верна. Если вы добавите его как fact(29,F), false., вы никогда не будете отвлекаться на красивые ответы.

Почему вы положили всю свою арифметику в конце? Я подозреваю, что раньше у вас были некоторые ошибки. Существует простой способ, чтобы избежать всех этих ошибок:

:- use_module(library(clpfd)). 

Вы пишете вместо is Теперь #=, и вам необходимо некоторое ограничение, как N #>= 1. Могу ли я оставить вас там?