Справка по Прологу - Не могу понять правило - PullRequest
0 голосов
/ 13 января 2012

У меня есть база данных, полная фактов, таких как:

overground( watfordjunction   , watfordhighstreet , 2 ).
overground( watfordhighstreet , bushey            , 3 ).
overground( bushey            , carpenderspark    , 3 ).
overground( carpenderspark    , hatchend          , 2 ).

пример: переход от Уотфорда до Уотфорд Хайстрит занимает 2 минуты.

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

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ ) ; 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .
isjourney( Station1 , Station2 ) :-
  overground( Station1 , Station3 , _ ) ,
  isjourney(  Station3 , Station2 )
  .
isjourney( Station1 , Station2 ) :-
  overground( Station4 , Station2 , _ ) ,
  isjourney(  Station1 , Station4 )
  .

(извините за подчеркивание, у меня были проблемы с их вставкой)

В конце концов я придумал то, чтоработает нормально, однако мне удалось придумать его только после проб и ошибок, поэтому я не могу объяснить, как он работает или даже что он делает ... Может кто-нибудь, имеющий опыт с прологом, объяснить мне, что он делает?

Ответы [ 3 ]

1 голос
/ 13 января 2012

Я предполагаю, что вы посещаете тот же класс, что и @DavidGregg. Мой ответ на https://stackoverflow.com/questions/8789021/basic-prolog-but-struggling/8794162#8794162 может вам помочь.

FWIW, переменная пролога _ является анонимной / " не волнует " переменной. Переменная с именем типа ____ является , а не анонимной / " не волнует ". Анонимная переменная объединяется с чем угодно, и объединение не переносится, поэтому такие факты, как:

number(1).
letter(a).

предикат, такой как

foo :- number(_) , letter(_).

будет успешным, тогда как

foo :- number(____) , letter(____) .

не будет.

В вашем первом предложении

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ ) ; 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .

Вы уверены, что это так, как вы думаете?

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

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ )
  .
isjourney( Station1 , Station2 ) :- 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .

Однако ваша основная мысль верна: существует маршрут между двумя станциями A и B , если

  • станция А существует, а
  • станция B существует, а
  • существует прямой маршрут между станцией A и некоторой промежуточной станцией X, и
  • существует маршрут между этой промежуточной станцией X и станцией B

Я полагаю, что вы пропустили один случай: станция A и станция B находятся рядом.

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

Я был бы склонен написать предикат что-то вроде

isjourney(A,B) :-
  station_exists(A) ,   % verify that station A exists
  station_exists(B) ,   % verify that station B exists
  (
    route_exists(A,B)   % verify that a route exists between A and B
    ;                   % in either direction
    route_exists(B,A)
  )
  .

route_exists(A,B) :- % 1st, check for directly adjacent stations
  overground(A,B,_) ,
  .
route_exists(A,B) :- % 2nd, check for indirect routes
  overground(A,T,_) ,
  route_exists(T,B)
  .

% =========================================================
% check for the existence of a station
% we want the cut to alternatives. A station exists or it doesn't
% we don't want backtracking to succeed by finding every instance
% of the station
% in the route map.
% =========================================================
station_exists(X) :- overground(X,_,_) , ! .
station_exists(X) :- overground(_,X,_) , ! .

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

Как отмечено в моем ответе, связанном с вышеупомянутым, решение все еще уязвимо для бездонной рекурсии, если на графике существует цикл (например, если станция A связана с станцией B, а станция B связана с обеими станциями C и A). ). Обнаружение таких циклов оставлено вам.

1 голос
/ 13 января 2012

Ваш первый пункт неверен. Должно быть

isjourney(Station1, Station2):- 
  overground(Station1, Station2, _).

Другие пункты выглядят нормально, но вы можете поместить их в один пункт:

isjourney(Station1,Station2):-
    (overground(Station1,Station3,_), isjourney(Station3,Station2)) ; 
    (overground(Station3,Station2,_), isjourney(Station1,Station3)) .

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

0 голосов
/ 13 января 2012

Я полагаю, вы пытаетесь ответить тем же, что и человек в этом вопросе .

Прежде всего, вы должны использовать свой ответ на вопрос 2:

Базовый случай, если есть прямое путешествие:

is_journey(Station1, Station2) :-
    q2(Station1, Station2).

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

is_journey(Station1, Station2) :-
    q2(Station1, StationTemp),
    is_journey(StationTemp, Station2).

Теперь, это не будет обрабатывать циклы: вы 'Вероятно, вы попадете в бесконечные циклы, поэтому для их обработки вы должны использовать:

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

is_journey(Station1, Station2) :-
    is_journey(Station1, Station2, [Station1]).

Затем мы используем тот же базовый случай:

is_journey(Station1, Station2, _) :-
    q2(Station1, Station2).

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

is_journey(Station1, Station2, Visited) :-
    q2(Station1, StationTemp),
    \+ member(StationTemp, Visited),
    is_journey(StationTemp, Station2, [StationTemp|Visited]).

Кстати, я не думаю, что ваш предикат OP верен, поскольку он только проверяет, действительно ли обе станции являются станциями, а не являются ли они непосредственно подключенными.

...