«Цикл» в Прологе, заменяя цели на `fail` - PullRequest
0 голосов
/ 19 сентября 2019

В следующем коде:

bestof(Val, GT, Goal) :-
   retract(queue(WorstVal)),
   call(Goal),
   greater(GT, WorstVal, Val, GTVal),
   assertz(queue(GTVal)),
   fail;
   retract(queue(WorstVal)),
   Val = WorstVal.

Я вижу в отладчике (LPA Prolog), что после fail ing он выполняет call(Goal).Почему?

Я мог бы предположить, что это потому, что это последний предикат, который объединяет, но это не объясняет поведение, которое я вижу в решении, которое работает для меня (описано позже).

Как можноЯ заставляю fail вернуться в начало предиката?

Я нашел решение переместить retract(queue... внутрь в предикат greater.Это работает, но я не понимаю, что здесь происходит.

Итог - как Пролог выбирает, куда вернуться после fail ing?

1 Ответ

2 голосов
/ 20 сентября 2019

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

После fail Пролог должен начать резервировать вызовы, которые предшествовали сбою.В этом случае непосредственно предшествующая вещь - assertz(queue(GTVal)).Пролог отменит это, когда вернется, но не будет пытаться повторить его, потому что это предикат детерминированный : он выдает только одно решение, поэтому нет причин для его повторения.Затем он возвращается к greater(GT, WorstVal, Val, GTVal).У меня нет кода передо мной, чтобы сказать вам, почему, но поведение, которое вы видите, говорит мне, что это также детерминированный предикат, поэтому в стеке не осталось точек выбора для повторной попытки Пролога здесь.Если какие-либо привязки были установлены, Пролог устранит их и вернется к call(Goal).Обратите внимание, что установление привязок само по себе не приводит к появлению точки выбора.Должны быть оставшиеся варианты.

call(Goal) интересен, потому что он будет зависеть от того, что Goal является ли это детерминированным или нет.Например, call(true) является детерминированным, а call(member(X, [1,2])) - нет.Поведение, которое вы видите, указывает на то, что это не так.Вы всегда можете получить полудетерминированное поведение (один успех или неудача), заключив свою цель в once/1, как в once(call(Goal)).Это самый простой и безопасный способ ввести сокращения в вашу программу;более общий механизм с оператором !.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...