Требуется рекурсивный оператор выхода l oop - PullRequest
0 голосов
/ 27 марта 2020

это простой пример пролога рекурсии. Я не могу понять, где и более или менее как объявить оператор выхода. Тестовый полет (София, Дублин) должен вернуть true, но на последних шагах он продолжает проверять, можете ли вы использовать directFlight (Дублин, Дублин). Вот код:

directFlight(sofia, varna).
directFlight(sofia, paris).
directFlight(sofia, london).
directFlight(london, edinburg).
directFlight(paris, new_york).
directFlight(new_york, seattle).
directFlight(london, dublin).

flight(City1, City2) :- 
   directFlight(City1, City3),      
   flight(City3, City2).

Выход:

 [trace]  ?- flight(sofia, dublin).
   Call: (8) flight(sofia, dublin) ? creep
   Call: (9) directFlight(sofia, _878) ? creep
   Exit: (9) directFlight(sofia, varna) ? creep
   Call: (9) flight(varna, dublin) ? creep
   Call: (10) directFlight(varna, _878) ? creep
   Fail: (10) directFlight(varna, _878) ? creep
   Fail: (9) flight(varna, dublin) ? creep
   Redo: (9) directFlight(sofia, _878) ? creep
   Exit: (9) directFlight(sofia, paris) ? creep
   Call: (9) flight(paris, dublin) ? creep
   Call: (10) directFlight(paris, _878) ? creep
   Exit: (10) directFlight(paris, new_york) ? creep
   Call: (10) flight(new_york, dublin) ? creep
   Call: (11) directFlight(new_york, _878) ? creep
   Exit: (11) directFlight(new_york, seattle) ? creep
   Call: (11) flight(seattle, dublin) ? creep
   Call: (12) directFlight(seattle, _878) ? creep
   Fail: (12) directFlight(seattle, _878) ? creep
   Fail: (11) flight(seattle, dublin) ? creep
   Fail: (10) flight(new_york, dublin) ? creep
   Fail: (9) flight(paris, dublin) ? creep
   Redo: (9) directFlight(sofia, _878) ? creep
   Exit: (9) directFlight(sofia, london) ? creep
   Call: (9) flight(london, dublin) ? creep
   Call: (10) directFlight(london, _878) ? creep
   Exit: (10) directFlight(london, edinburg) ? creep
   Call: (10) flight(edinburg, dublin) ? creep
   Call: (11) directFlight(edinburg, _878) ? creep
   Fail: (11) directFlight(edinburg, _878) ? creep
   Fail: (10) flight(edinburg, dublin) ? creep
   Redo: (10) directFlight(london, _878) ? creep
   Exit: (10) directFlight(london, dublin) ? creep
   Call: (10) flight(dublin, dublin) ? creep
   Call: (11) directFlight(dublin, _878) ? creep
   Fail: (11) directFlight(dublin, _878) ? creep
   Fail: (10) flight(dublin, dublin) ? creep
   Fail: (9) flight(london, dublin) ? creep
   Fail: (8) flight(sofia, dublin) ? creep
false.

Проблема здесь: Fail: (10) рейс (Дублин, Дублин)? ползать. Есть идеи как это исправить?

1 Ответ

6 голосов
/ 27 марта 2020

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

Вы начинаете с сети узлов, соединенных набором ребер ( отношение).

В этом случае узлы представлены атомами (обозначающими города), набор ребер отношения называется directFlight/2.

direct flights

Теперь вы хотите наложить еще один набор ребер, который называется flight/2.

Поэтому вы должны спросить себя, когда у меня есть flight/2 ребро между двумя атомами A и B

Существует два случая:

  1. Если между ними есть directFlight/2 (базовый случай)
  2. Если существует промежуточный узел I таким, что существует flight/2 от A до I и directFlight/2 между I и B.
  3. В качестве альтернативы, если существует промежуточный узел I, такой что существует directFlight/2 между A и I и flight/2 от I до B.

Пролог найдет flight/2 край сам по себе при запросе

flight(sofia, dublin).

(так же, как реляционная база данных находит результат запроса SQL), но вы должны обратить внимание на завершение. Альтернативный случай (3) выше приведет к успешному поиску или «ложь». Случай (2) приведет к не прекращению - полностью из-за стратегии поиска Пролога (где должны быть приняты решения о том, как машина реального мира выполняет поиск в сети, в данном случае, сначала в глубину, в крайнем левом направлении).

Вот базовый случай для flight/2 (первое изображение), все flight/2, выведенные рекурсией 1 глубокого вызова, и все flight/2, выведенные рекурсией 2 глубоких вызовов.

flights

Итак:

directFlight(sofia, varna).
directFlight(sofia, paris).
directFlight(sofia, london).
directFlight(london, edinburg).
directFlight(paris, new_york).
directFlight(new_york, seattle).
directFlight(london, dublin).

flight(City1, City2) :- directFlight(City1, City2).
flight(City1, City2) :- directFlight(City1, City3), flight(City3, City2).

А затем:

?- flight(sofia,dublin).
true ;
false.

?- flight(sofia,X).
X = varna ;
X = paris ;
X = london ;
X = new_york ;
X = seattle ;
X = edinburg ;
X = dublin ;
false.

?- flight(X,sofia).
false.

Приложение 1

Выше Программа может быть прочитана:

  • "от ВЛЕВО: - ВПРАВО " (как это делает Пролог). Это поиск, чтобы установить, имеет ли место факт flight/2 или могут быть найдены значения, которые делают его истинным.
  • "от ВПРАВО -: ВЛЕВО ". Ментальный образ постоянно накапливает новые факты о flight/2, пока не соберет их все и больше ничего не будет добавлено: поиск снизу вверх (это как-то легче для мозга, по крайней мере для меня). Безопаснее, чем поиск, так как вы не рискуете попасть в бесконечный провал рекурсии только потому, что предложения расположены неудачно, и это то, что делают некоторые реализации Datalog.

Логическое чтение (или 2) оператор («программа»), который задает ограничения на то, как flight/2 должен быть структурирован:

∀(City1, City2) : 
  (flight(City1, City2) <= 
     directFlight(City1, City2))
∧

∀(City1, City2) :
  (flight(City1, City2) <= 
     (∃City3: directFlight(City1, City3) ∧ flight(City3, City2))

Обратите внимание, что в приведенном выше нет ничего, что исключало бы, что flight(X,Y) может выполняться для ДРУГОГО причины, чем заявлено. Мы предполагаем, однако, что мы знаем все о том, когда flight(X,Y) имеет место: Предположение о закрытом мире.

Приложение 2

Часто забывают, что рекурсивного вызова вообще не требуется. Рекурсию можно «развернуть», а прямое связывание можно сделать явным:

directFlight(sofia, varna).
directFlight(sofia, paris).
directFlight(sofia, london).
directFlight(london, edinburg).
directFlight(paris, new_york).
directFlight(new_york, seattle).
directFlight(london, dublin).

flight(City1, City2) :- directFlight(City1, City2).
flight(City1, City2) :- directFlight(City1, Ia),
                        directFlight(Ia, City2).
flight(City1, City2) :- directFlight(City1, Ia),
                        directFlight(Ia, Ib), 
                        directFlight(Ib, City2).
flight(City1, City2) :- directFlight(City1, Ia),
                        directFlight(Ia, Ib),
                        directFlight(Ib, Ic),
                        directFlight(Ic, City2).

Ни один из городов не расположен на расстоянии более 3 прыжков, поэтому вышеуказанная программа найдет все flight/2 соединений.

На самом деле, другим упражнением было бы создание вышеуказанной программы с указанием в качестве аргумента "максимальной глубины".

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