Устойчивость: определение и его связь с логической чистотой и прекращением

До сих пор я всегда придерживался устойчивости в программах Prolog:

Если для запроса Q существует подтерм S, так что существует термин T, который делает ?- S=T, Q. успешным, хотя ?- Q, S=T. не работает, тогда один из предикатов, вызываемый Q, будет не стойким.

Интуитивно я утверждал, что мы не можем использовать экземпляры, чтобы "обмануть" предикат, чтобы дать решения, которые иначе не только не даны, но отклонено. Обратите внимание на разницу для неисчерпающих программ!

В частности, по крайней мере, для меня всегда подразумевала стойкость.


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

integer_integer_maximum(X, Y, Y) :-
        Y >= X,
        !.
integer_integer_maximum(X, _, X).

Вопиющая ошибка в этом вопросе: скажем, определение "колебания" означает, что следующий запрос неправильно преуспевает:

?- M = 0, integer_integer_maximum(0, 1, M).
M = 0. % wrong!

тогда как обмен целями дает правильный ответ:

?- integer_integer_maximum(0, 1, M), M = 0.
false.

Хорошим решением этой проблемы является полагаться на чистые методы для описания отношения, используя, например:

integer_integer_maximum(X, Y, M) :-
        M #= max(X, Y).

Это корректно работает в обоих случаях и может использоваться даже в следующих ситуациях:

?- integer_integer_maximum(0, 1, M), M = 0.
false.

?- M = 0, integer_integer_maximum(0, 1, M).
false.

| ?- X in 0..2, Y in 3..4, integer_integer_maximum(X, Y, M).
X in 0..2,
Y in 3..4,
M in 3..4 ? ;
no


Теперь документ Руководства по кодированию для Prolog Ковингтона и др., в соавторстве с самим изобретателем понятия Ричард О "Keefe" содержит следующий раздел:

5.1 Предикаты должны быть стойкими.

Любой достойный предикат должен быть "стойким", то есть должен работать правильно, если его выходная переменная уже используется для создания выходного значения (OKeefe 1990).

То есть

?- foo(X), X = x.

и

?- foo(x).

должен преуспеть при одинаковых условиях и иметь одинаковые побочные эффекты. Несоблюдение этого допускается только для вспомогательных предикатов, чьи шаблоны вызовов сильно ограниченные основными предикатами.

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

Например, рассмотрите программу pure Prolog:

nat(s(X)) :- nat(X).
nat(0).

Теперь мы находимся в следующей ситуации:

?- nat(0).
true.

?- nat(X), X = 0.
nontermination

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

Отсюда мой вопрос: нельзя ли назвать вышеупомянутую программу непоколебимой? Пожалуйста, оправдайте ваш ответ с объяснением намерения за стойкостью и его определение в доступной литературе, его отношение к , а также соответствующие понятия терминации.

Ответ 1

В "The craft of prolog" стр. 96 Ричард О'Киф говорит: "Мы называем свойство отказываться давать неправильные ответы, даже если запрос имеет неожиданную форму (обычно поставляя значения для того, что мы обычно считаем в качестве входов *) стойкость"

* Я не уверен, что это должны быть выходы. т.е. в вашем запросе ?- M = 0, integer_integer_maximum(0, 1, M). M = 0. % wrong! M используется как вход, но предложение было разработано для него как выход.

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

Правило большого пальца, которое он дает, это "отложить выходную унификацию до окончания разреза". Здесь у нас нет сокращения, но мы все же хотим отложить объединение.

Однако я бы подумал, что было бы разумно иметь базовый случай сначала, а не рекурсивный случай, так что nat(X), X = 0. изначально преуспел бы... но у вас все еще были бы другие проблемы.