Во-первых, давайте протестируем ваше решение:
?- pythag(X,Y,Z,20).
X = 4,
Y = 3,
Z = 5 ;
X = 3,
Y = 4,
Z = 5 ;
X = 8,
Y = 6,
Z = 10 ;
X = 6,
Y = 8,
Z = 10 ;
X = 12,
Y = 5,
Z = 13 ;
X = 5,
Y = 12,
Z = 13 ;
X = 12,
Y = 9,
Z = 15 ;
X = 9,
Y = 12,
Z = 15 ;
X = 15,
Y = 8,
Z = 17 ;
X = 8,
Y = 15,
Z = 17 ;
X = 16,
Y = 12,
Z = 20 ;
X = 12,
Y = 16,
Z = 20 ...
Мне кажется идеально! Все ответы являются правильными решениями! ... вплоть до этого последнего решения. После этого ваша программа зацикливается.
Прежде чем мы попытаемся определить проблему, просто задержитесь на мгновение: вы должны быть очень терпеливы, чтобы просмотреть 12 (то есть двенадцать) ответов только для того, чтобы найти эту петлю. Считаете ли вы, что этот метод также будет работать для больших случаев? Сколько ответов вы готовы просмотреть, прежде чем сдаться? Нет ли более простого способа узнать о проблеме?
Здесь есть одно интересное наблюдение: найденные ответы не имеют (почти) ничего общего с зацикливанием программы! То есть: просматривая ответы, вы не получаете (часто, как в этом случае) никакого понятия о фактической причине петли! Так почему бы не отключить все ответы и не сосредоточиться на соответствующей части! На самом деле мы можем сделать это следующим образом:
?- pythag(X,Y,Z,20), false.
** LOOP **
Теперь все ответы удалены из-за цели false
. Остается только конечный результат: либо прекращение, либо не прекращение, либо какая-то ошибка. Ничего больше. Это должно немного облегчить наши наблюдения по поводу завершения — больше никаких ослепляющих ответов, прокручивающихся на экране. Обратите внимание, что это не решает проблему в целом. В конце концов, сколько долго мы готовы ждать? 1с? 1м?
Истинную причину отказа можно лучше всего понять, взглянув на соответствующий срез сбоя. Это фрагмент программы, незавершение которого подразумевает незавершение всей программы. Дополнительные сведения см. в этом ответе . Вот соответствующий срез вашей программы для запроса pythag(X,Y,Z,20), false
:
pythag(X,Y,Z,N) :-
int_triple(X,Y,Z,N), false,
Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :-
is_int(S), false,
minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
is_int(0) :- false.
is_int(X) :-
is_int(Y), false,
X is Y+1.
Обратите внимание, что от вашей программы осталось не так много вещей. Например, фактическое уравнение исчезло (это более или менее логическая часть...). Тем не менее, этот фрагмент актуален. И пока вы ничего не измените в этом фрагменте, проблема не исчезнет! Это гарантировано для чистой монотонной программы, такой как эта...
Вот мое предпочтительное решение: оно использует length/2
и between/3
, два часто поддерживаемых предиката Пролог Пролога.
pythag2(X,Y,Z,N) :-
length(_, N),
between(1,N,X),
between(1,N,Y),
between(1,N,Z),
Z*Z =:= X*X + Y*Y.
person
false
schedule
09.05.2012