2011-01-29 6 views
7

У меня есть следующий фрагмент кода пролога:Почему эта команда вызывает переполнение стека в прологе?

num(0). 
num(X) :- num(X1), X is X1 + 1. 

fact(0,1) :-!. 
fact(X,Y) :- X1 is X-1, fact(X1,Y1), !, Y is Y1 * X. 

fact(X) :- num(Y), fact(Y,X). 

Может кто-нибудь, пожалуйста, объясните, почему следующая команда вызывает переполнение стека? Заранее спасибо.

fact(6). 

ответ

2

Во-первых, глядя на правила

num(0). 
    num(X) :- num(X1), X is X1 + 1. 

предикат num(Y) будет немедленно справедливо для Y = 0.

Таким образом, правило

fact(X) :- num(Y), fact(Y,X). 

может быть упрощена

fact(X) :- fact(0,X). 

, который будет найти соответствие для fact(0,1). Для X = 6, что происходит вместо этого, поскольку ни одно правило не определяет предикат для fact(0,6), поиск начинается с fact(-1,V1), а затем fact(-2,V2) и т. Д. ... до совпадения для fact(-value, Var), где локальный результат будет найден Var.

Этого не может быть, и бесконечный цикл потребляет весь стек, пока не будет вызвана ошибка.

+3

Возможно, вам следует указать на то, чтобы новобранец, что проблема, которую вы проанализировали можно предотвратить путем добавления 'X> 0' к корпусу 2-го пункта для ** факта/2 **. – hardmath

2

Причина fact(6) не прекращается, можно найти в следующем :

 
?- fact(6). 

num(0) :- false. 
num(X) :- 
    num(X1), false, 
    X is X1 + 1. 

fact(X) :- 
    num(Y), false, 
    fact(Y,X). 

Поскольку этот фрагмент не прекращается, и ваша оригинальная программа не завершается. Обратите внимание, что исключение не зависит от определения fact/2! В лучшем случае ваша программа может преуспеть, но она никогда не (окончательно) потерпит неудачу.

Рассмотрим использование another definition of fact/2, который заканчивается также fact(N, 6).