Пролог конструкции if-then-else: -> vs *-> vs. if_/3
Как отмечалось в другом ответе Stackru, который я больше не могу найти, этот шаблон часто появляется в практическом коде Prolog:
pred(X) :-
guard(X),
...
pred(X) :-
\+ guard(X),
...
и многие люди пытаются сжать это
pred(X) :-
(guard(X) ->
...
;
...).
Однако, как мы все знаем, структура стрелок разрушает точки выбора и не логична.
В книге Ульриха Ноймеркеля и Стефана Крала dif / 2 предикат называется if_/3
предлагается монотонно и логично, однако в статье упоминается еще одна конструкция, которая привлекла мое внимание: *->
,
*->
Создайте функции в точности так же, как в приведенном выше примере с невыраженной защитой, и, таким образом, он кажется идеальным для моих целей, так как я не хочу иметь условное условие, которое требуется if_/3
и мне наплевать на дополнительные пункты выбора. Если я не ошибаюсь (правка), он предлагает ту же семантику, что и if_/3
но без требования добавления "reification" к предикату условия.
Однако в документации SWI для него говорится, что "эта конструкция используется редко", что мне кажется странным. *->
мне кажется, что это строго лучше, чем ->
когда вы пытаетесь сделать чисто логическое программирование. Есть ли какая-либо причина избегать этой структуры, или есть даже лучшая альтернатива всей структуре охранного предложения / отрицательного защитного предложения?
2 ответа
Давайте попробуем это! Шаблон, который вы даете:
пред (X):- (охранник (X) -> ...; ...).
Я сейчас пользуюсь (*->)/2
и заполните "..." следующим образом:
пред (X): - (охранник (X) * -> ложный; правда).
Далее, как guard/1
Я определяю очевидно чистый предикат:
охранник (а).
Теперь давайте спросим pred/1
самый общий вопрос: есть ли какие-либо решения вообще?
? - пред (X). ложный.
Итак, согласно предикату, нет термина X
такой, что pred(X)
это правда.
Но это неправильно, потому что на самом деле существует такой термин:
? - Пред (б). правда.
По факту, pred/1
имеет бесконечно много решений. Приемлемо ли в такой ситуации, что предикатные состояния вообще отсутствуют? Конечно, потому что ответ был рассчитан очень эффективно, не так ли?
Мы заключаем, что (*->)/2
разделяет важный недостаток (->)/2
: Он может неправильно зафиксировать одну из ветвей в тех случаях, когда другая ветвь будет применима, если будут дополнительно созданы только переменные, которые встречаются в условии. Предикат, который зависит от реализации его аргументов таким образом, никогда не может быть чистым, потому что он противодействует монотонному рассуждению, которое мы ожидаем применить к программам с чистой логикой. В частности, с логической точки зрения, так как pred(b)
держит, мы ожидаем, что pred(X)
, который является обобщением pred(b)
, не должен подвести. Когда это свойство нарушается, вы больше не можете применять декларативную отладку и другие важные подходы, которые позволяют вам более легко понимать, рассуждать о программах Prolog и управлять ими, и которые представляют собой главную привлекательность декларативного программирования в первую очередь.
Вопрос, который вы упомянули, вероятно, что использует if_3/
есть?,
Обычно называемая мягкая управляющая конструкция доступна в нескольких системах Prolog. CxProlog, ECLiPSe, JIProlog, SWI-Prolog и YAP предоставляют его как *->/2
предикат и инфиксный оператор. Ciao Prolog, SICStus Prolog и YAP обеспечивают if/3
Предикат с той же семантикой.
Мое основное использование этой мягкой управляющей конструкции - реализация коиндукции в Logtalk, где она играет критическую роль. За пределами этого случая я редко использую его.
->/2
с другой стороны, он широко используется. Неявное сокращение части if является локальным по отношению к конструкции, и ее использование позволяет избежать, как в вашем примере, попытки дважды доказать защиту, что может быть вычислительно дорогостоящим. Это может быть не чисто, но, как и в случае с разрезом, если вы полностью осведомлены о его плюсах и минусах, это полезная управляющая конструкция.
PS Logtalk предоставляет модульные тесты для этой конструкции управления для *->/2
вариант на https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/soft_cut_2_3 и для if/3
вариант на https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/if_3