Пролог: ошибка выхода из глобального стека с тем, что мне кажется ОДНИМ уровнем рекурсии

Я довольно ржавый в прологе, но я не уверен, почему такие вещи терпят неудачу:

frack(3).

frack(X) :- frack(X-1).

Итак, если я оцениваю frack(4). из интерактивной подсказки с указанными выше фактами я ожидаю, что она не должна бесконечно повторяться, поскольку 4-1 = 3. Но я получаю эту ошибку в SWI-Prolog:

ERROR: Out of global stack

person Warren P    schedule 10.02.2012    source источник


Ответы (4)


Попробуй:

?- 4-1 = 3.
false.

Почему? Потому что 4-1 = -(4, 1), что явно не число, а составной термин.

Чтобы рассуждать о целых числах в Прологе, используйте ограничения clpfd, например (с использованием GNU Prolog или B-Prolog):

| ?- 4-1 #= X.

X = 3

В SWI-Prolog вам может пригодиться графический трассировщик, чтобы увидеть, что происходит:

?- gtrace, frack(4).

Для более сложной отладки я рекомендую failure-slice как показано в ложном ответе.

person mat    schedule 10.02.2012
comment
Я не знал, что у SWI такое есть. Хороший! - person Warren P; 10.02.2012

Вот причина этого непрекращения. Ваш запрос не завершается, потому что сбой -slice вашей программы, которая не завершается:

?- frack(4).

frack(3) :- false.
frack(X) :-
   frack(X-1), false.

Исправить это можно только изменив что-то в видимой части. Три SO-ответа предлагают использовать (is)/2. Но это не уберет незавершенность! На самом деле использование (is)/2 приводит к тому же самому фрагменту:

?- frack(4).

frack(3) :- false.
frack(X) :-
   Y is X - 1,
   frack(Y), false.

По крайней мере, frack(4) теперь выполняется успешно, но при откате он зациклится. Вы должны что-то изменить в видимой части, например, какой-то тест для X, чтобы избежать нетерминации. Дополнительную информацию см. в разделе failure-slice.

person false    schedule 15.11.2012

frack(X) :- frack(X-1).

должно быть

frack(X) :- Y is X - 1, frack(Y).

Как вы написали, X-1 выражение первого уровня объединяет с X переменной следующего уровня, никогда не переходя на frack(3) факт.

person Sergey Kalinichenko    schedule 10.02.2012
comment
Спасибо за использование слова Unified. Теперь это снова имеет смысл. В последний раз я делал пролог в 1989 году. Это было давно. - person Warren P; 10.02.2012
comment
@WarrenP Вау, так ты старожил по сравнению со мной! В последний раз я делал Пролог в 1996 году :) - person Sergey Kalinichenko; 10.02.2012
comment
Ваше решение все еще не заканчивается. - person false; 15.11.2012
comment
@false Почему бы ему не прекратиться, если факт frack(3). ОП все еще на месте, и он передает 4? - person Sergey Kalinichenko; 15.11.2012
comment
@dasblinkenlight: frack(4) действительно находит решение, но не прекращает работу. Очень старые верхние уровни не запрашивали дальнейших решений, если цель была измельчена. Так люди думали, что все работает. Однако, когда позже они использовали код в другом контексте, петля возникла в самый неподходящий момент. Подумайте о setof(X,(X=1,frack(4)),_). По этой причине более новые верхние уровни (например, в SWI, YAP, B, GNU) всегда запрашивают дополнительные ответы, при условии, что (внутренне) остается точка выбора. Таким образом, такие скрытые циклы могут быть обнаружены раньше (подробнее см. failure-slice). - person false; 15.11.2012
comment
@false Ах, интересно знать. Моей последней средой выполнения Prolog был Quintus еще в 1996 году, с тех пор я никогда не прикасался к Prolog, кроме как ответить на несколько вопросов по SO. - person Sergey Kalinichenko; 15.11.2012
comment
@dasblinkenlight: Или возьми frack(2). Для многих целей лучший верхний уровень в настоящее время находится в SWI. - person false; 15.11.2012
comment
@false Мне любопытно, исправит ли добавление frack(3) :- !. незавершенность вызовов frack(X) с X выше 3? - person Sergey Kalinichenko; 15.11.2012
comment
@dasblinkenlight: Выше 3, да. Но не для frack(2). Обычно у вас есть какие-то дополнительные аргументы, которые еще больше усложняют понимание таких сокращений. Я лично предпочитаю в любом случае clpfd - вот так - person false; 15.11.2012

Пролог не выполняет арифметические действия, если вы не используете оператор is:

frack(X) :- X1 is X-1, frack(X1).
person Scott Hunter    schedule 10.02.2012