Пролог конструкции if-then-else: - ›vs * -› vs. if_ / 3

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

pred(X) :-
    guard(X),
    ...
pred(X) :-
    \+ guard(X),
    ...

и многие люди пытаются сжать это до

pred(X) :-
    (guard(X) ->
    ...
    ;
    ...).

Однако, как все мы знаем, структура стрелок разрушает точки выбора и не логична.

В Indexing dif / 2 предиката, называемого if_/3, Ульриха Ноймеркеля и Стефана Краля предлагается, что монотонно и логично, однако в статье упоминается еще одна конструкция, которая привлекла мое внимание: *->.

Конструкция *-> функционирует в точности так же, как и приведенный выше пример с несахарным защитным условием, и, таким образом, кажется идеальным для моих применений, поскольку я не хочу иметь овеществленное условие, которое требуется if_/3, и мне наплевать на дополнительные точки выбора. Если я не ошибаюсь (отредактируйте: я), он предлагает ту же семантику, что и if_/3, но без требования добавления «реификации» к предикату условия.

Однако в документации SWI для него утверждается, что " эта конструкция используется редко », что мне кажется странным. *-> мне кажется, что это строго лучше, чем ->, когда вы пытаетесь заниматься чисто логическим программированием. Есть ли причина избегать этой структуры, или есть еще лучшая альтернатива всему шаблону защитного предложения / отрицательного защитного предложения?


person Name McChange    schedule 31.10.2018    source источник
comment
Если я не ошибаюсь, он предлагает ту же семантику, что и if_/3. Вы ошибаетесь. См. 2 Декларативные ограничения if-then-else в Prolog, последний абзац: Даже «мягкие» версии if/3 и (*->)/2 SICStus и SWI соответственно демонстрируют те же проблемы, что и Необоснованное отрицание Пролога.   -  person false    schedule 31.10.2018
comment
Вот определение if/3 (неэффективно, поскольку он запускает охрану дважды): if(G_0, Then_0, _) :- G_0, Then_0. if(G_0, _, Else_0) :- \+ G_0, Else_0. Вы видите \+? Он полон нечистоты!   -  person false    schedule 01.11.2018


Ответы (2)


Давай попробуем! Образец, который вы даете:

pred(X) :-
    (    guard(X) ->
         ...
    ;    ...
    ).

Теперь я использую (*->)/2 и заполняю "..." следующим образом:

pred(X) :-
        (   guard(X) *->
            false
        ;   true
        ).

Далее, как guard/1, я определяю явно чистый предикат:

guard(a).

Теперь давайте зададим pred/1 самый общий вопрос: Есть ли вообще какие-нибудь решения?

?- pred(X).
false.

Итак, согласно предикату, не существует термина X, для которого pred(X) истинно.

Но это неправильно, потому что на самом деле существует такой термин:

?- pred(b).
true.

Фактически, pred/1 имеет бесконечно много решений. Допустимо ли в такой ситуации, что предикатные состояния вообще отсутствуют? Конечно, потому что ответ был вычислен чрезвычайно эффективно, не так ли?

Мы пришли к выводу, что (*->)/2 разделяет важный недостаток (->)/2: он может неправильно выполнить фиксацию в одной из ветвей в тех случаях, когда другая ветвь будет применима, если только переменные, которые встречаются в условие было дополнительно инстанцировано. Предикат, который зависит от реализации своих аргументов таким образом, никогда не может быть чистым, потому что он противодействует монотонным рассуждениям, которые, как мы ожидаем, применимы к программам на чистой логике. В частности, с логической точки зрения, поскольку pred(b) выполняется, мы ожидаем, что pred(X), который является обобщением pred(b), не должен потерпеть неудачу. Как только это свойство нарушится, вы больше не сможете применять декларативную отладку и другие важные подходы, которые позволяют вам легче понимать, рассуждать и управлять программами Prolog и которые в первую очередь составляют главную привлекательность декларативного программирования.

Вы упомянули вопрос, вероятно, Какое применение имеет if_3/? < / а>.

person mat    schedule 31.10.2018
comment
Хорошо, теперь я понял. Мне кажется, что если бы мы заставили \+/1 работать так же, как dif/2 (то есть наложили ограничение, что определенное выражение никогда не будет доказано), мы могли бы добиться правильного поведения *->, сделав его таким, чтобы если тест предложение не работает (например, guard(X)), оно вводит ограничение \+guard(X), и мы могли бы избежать всего обходного пути реификации для предложений if_/3, не так ли? - person Name McChange; 31.10.2018
comment
Обратите внимание, что заставить (\+)/1 работать так же, как dif/2, равносильно конструктивному отрицанию. Вы найдете обсуждение этого в 7 Общее овеществление. По крайней мере, исходя из приведенного примера, общее овеществление намного дороже по сравнению со всем обходным путем if_/3. - person false; 31.10.2018
comment
@false Замечательно, спасибо за подсказку. Кажется, что мы можем добиться чистого поведения, изменив исходный пример на freeze(X, \+guard(X)), и похоже, что он работает так же, как форма if_/3. Однако я не уверен в последствиях этого для производительности. - person Name McChange; 31.10.2018
comment
@NameMcChange: в зависимости от очень точного значения guard/1 вам может понадобиться when(ground(X), \+ guard(X)) или что-то среднее. Именно поэтому конструктивное отрицание так дорого обходится. Вам нужен более или менее метаинтерпретатор, который следит за поведением guard/1. - person false; 31.10.2018

Обычно называемая управляющая конструкция soft-cut доступна в нескольких системах Prolog. CxProlog, ECLiPSe, JIProlog, SWI-Prolog и YAP предоставляют его как предикат *->/2 и инфиксный оператор. Ciao Prolog, SICStus Prolog и YAP предоставляют предикат if/3 с той же семантикой.

Я использую эту конструкцию soft-cut в основном для реализации коиндукции в Logtalk, где она играет важную роль. Вне этого случая пользуюсь редко.

->/2, с другой стороны, широко используется. Неявный разрез в части if является локальным по отношению к конструкции, и его использование позволяет избежать, как в вашем примере, попытки дважды доказать защиту, что может быть дорогостоящим в вычислительном отношении. Он может быть не чистым, но, как и в случае с сокращением, до тех пор, пока вы полностью осведомлены о его плюсах и минусах, это полезная конструкция элемента управления.

P.S. Logtalk предоставляет модульные тесты для этой управляющей конструкции для варианта *->/2 по адресу https : //github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/soft_cutif/33 и для варианта if/3 на https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/if_3

person Paulo Moura    schedule 31.10.2018