Контроль предикатов в Прологе - PullRequest
9 голосов
/ 06 ноября 2010

Имейте любопытство, связанное с предикатным контролем Пролога.

Возможно, у меня есть предикат f (A, X) и g (B).

f(A,X):- a,b,c, g(X).
g(B):- true.

a - returns true
b - returns true.
c - returns false.
where a,b and c are random predicates.

Как я могу продолжать оценивать g(X) в предикате f(A,X), если c возвращает false?

Ответы [ 2 ]

9 голосов
/ 07 ноября 2010

Если вы намерены определить f(A,X) таким образом, чтобы g(X) оценивалось независимо от того, не удастся ли c, то либо:

  1. Вы можете закодировать это с помощью импликации (->) и / или дизъюнкции (;), или
  2. f(A,X) не нужно определять в терминах c. Предполагается, что c не имеет побочных эффектов (например, утверждение фактов базы данных с использованием assert или печать ввода-вывода в поток), которые изменяют среду и не могут быть отменены при сбое c, в этом случае первый вариант предпочтительнее.

Существует несколько вариантов использования дизъюнкции, например:

f(A,X) :- ((a, b, c) ; (a, b)), g(X).

Это определение (выше) совсем не зависит от c, но оно всегда будет исполнять c (до тех пор, пока a и b будут успешными). Разъединение (;) позволяет PROLOG вернуться назад, чтобы попытаться выполнить a, b снова , если c вообще не удалось, и продолжить на g(X). Обратите внимание, что это эквивалентно:

f(A,X) :- a, b, c, g(X).
f(A,X) :- a, b, g(X).

Чтобы PROLOG не возвращался назад для оценки f(A,X) дважды из-за второго (идентичного) предиката головы f(A,X) для каждой оценки, вы можете выбрать сокращение (!), если ваша реализация его поддерживает , сразу после подцела c в первом предложении. Разрез ставится после c, потому что мы не хотим, чтобы интерпретатор подтвердил этот выбор условия f(A,X), если c потерпел неудачу, вместо этого мы хотим, чтобы интерпретатор вышел из этого и попробовать следующий, чтобы эффективно игнорировать c и продолжить обработку g(X).

Также обратите внимание, что это решение основано на a и b, не имеющих побочных эффектов, потому что, когда c не удается, a и b выполняются снова. Если у всех a, b и c есть побочные эффекты, вы можете попробовать использовать implication :

f(A,X) :- a, b, (c -> g(X) ; g(X)).

Это также будет эффективно всегда выполнять g(X) независимо от того, произойдет сбой c или нет, и не будет выполнять a и b снова, если произойдет сбой c. Это определение с одним предложением также не оставит точку выбора, как предыдущее предложение.

2 голосов
/ 07 ноября 2010

Полагаю, вы можете завернуть c в ignore/1. Рассмотрим, например,

?- false, writeln('Hello World!').
false.

?- ignore(false), writeln('Hello World!').
Hello World!
true.

Но почему вы хотите продолжить, если c не удается? Какой вариант использования?

Я тестировал этот код в SWI-Prolog, я не уверен, что другие прологи имеют false/0 и ignore/1. Последнее можно определить так:

ignore(Goal) :- Goal, !.
ignore(_).
...