Каковы возможности использования предиката fail в Prolog?

Я не могу придумать ситуацию, в которой он мне понадобится.

Ответы

Ответ 1

Элегантные системы предоставляют false/0 как декларативный синоним императива fail/0. Пример, когда это полезно, - это когда вы вручную хотите принудительно отступить для побочных эффектов, например:

?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3

Вместо false/0 вы также можете использовать любую цель, которая терпит неудачу, например, немного короче:

?- between(1,3,N), format("line ~w\n", [N]), 0=1.
line 1
line 2
line 3

Таким образом, false/0 не является строго необходимым, но довольно приятным.

РЕДАКТИРОВАТЬ. Иногда я вижу новичков, которые хотят указать, например, "мое отношение не выполняется для пустого списка", а затем добавьте:

my_relation([]) :- false.

к их коду. Это необязательно, и не является хорошим примером использования false/0, за исключением, например, фрагментов отказа, которые программно сгенерированы. Вместо этого сосредоточьтесь на том, чтобы говорить о том, что касается ваших отношений. В этом случае просто оставьте все предложение и определите отношение только для списков, которые не пусты, то есть имеют хотя бы один элемент:

my_relation([L|Ls]) :- etc.

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

my_relation(T) :- dif(T, []), etc.

Учитывая только (или даже оба) этих двух предложений, запрос ?- my_relation([]). будет автоматически терпеть неудачу. Нет необходимости вводить дополнительное предложение, которое никогда не удастся с этой целью.

Ответ 2

Явный сбой. fail часто используется совместно с cut: ... !, fail. для принудительного выполнения отказа.

Для всех конструкций. Явное использование fail/false для перечисления с помощью обратного отслеживания - это очень склонная к ошибкам активность. Рассмотрим случай:

... ( generator(X), action(X), fail ; true ), ...

Идея заключается в том, чтобы "делать" действие для всех X. Но что происходит, если action(X) терпит неудачу? Эта конструкция просто продолжается со следующим кандидатом -— как будто ничего не произошло. Таким образом, некоторые ошибки могут оставаться необнаруженными очень долго.

Для таких случаев лучше использовать \+ ( generator(X), \+ action(X) ), который терпит неудачу, если action(X) терпит неудачу для некоторого X. Некоторые системы предлагают это как встроенный forall/2. Лично я предпочитаю использовать \+ в этом случае, потому что \+ немного яснее, что конструкция не оставляет привязки.

Отказоустойчивость. В целях диагностики часто полезно добавлять целевые false в свои программы. Подробнее см. .

Ответ 3

Один случай (взятый из Программирование логики Constraint с использованием Eclipse) представляет собой реализацию not/1:

:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .

Если Q преуспевает, разрез (!) вызывает отключение второго некласса, а сбой - отрицательный результат. Если Q терпит неудачу, то сначала начинается первое неклассическое предложение.

Ответ 4

Еще одно использование для сбоя - принудительное возвращение по альтернативам при использовании предикатов с побочными эффектами:

writeall(X) :- member(A,X), write(A), fail.
writeall(_).

Некоторые люди могут не учитывать этот особенно хороший стиль программирования.:)