Когда Redo-порт вызывается с новыми переменными в Trace/0, а когда нет?
Во время моей реализации игры Adventure в Прологе мне было интересно, когда повторный порт вызывается с новыми переменными во время возврата и когда он вызывается с теми же самыми?
Например, у меня есть следующая база знаний:
location(desk,office).
location(apple,kitchen).
location(flashlight,desk).
location('washing machine',cellar).
location(nani,'washing machine').
location(broccoli,kitchen).
location(crackers,kitchen).
location(computer,office).
door(office,hall).
door(kitchen,office).
door(hall,'dining room').
door(kitchen,cellar).
door('dining room',kitchen).
При трассировке запроса ?-(location(X,Y),door(kitchen,Y)).
Я получаю это:
Call: (9) location(_7998, _8000) ? creep
Exit: (9) location(desk, office) ? creep
Call: (9) door(kitchen, office) ? creep
Exit: (9) door(kitchen, office) ? creep
X = desk,
Y = office ;
Redo: (9) door(kitchen, office) ? creep <==== 1
Fail: (9) door(kitchen, office) ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location(apple, kitchen) ? creep
Call: (9) door(kitchen, kitchen) ? creep
Fail: (9) door(kitchen, kitchen) ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location(flashlight, desk) ? creep
Call: (9) door(kitchen, desk) ? creep
Fail: (9) door(kitchen, desk) ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location('washing machine', cellar) ? creep
Call: (9) door(kitchen, cellar) ? creep
Exit: (9) door(kitchen, cellar) ? creep
X = 'washing machine',
Y = cellar ;
Redo: (9) location(_7998, _8000) ? creep <==== 2
Exit: (9) location(nani, 'washing machine') ? creep
Call: (9) door(kitchen, 'washing machine') ? creep
Fail: (9) door(kitchen, 'washing machine') ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location(broccoli, kitchen) ? creep
Call: (9) door(kitchen, kitchen) ? creep
Fail: (9) door(kitchen, kitchen) ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location(crackers, kitchen) ? creep
Call: (9) door(kitchen, kitchen) ? creep
Fail: (9) door(kitchen, kitchen) ? creep
Redo: (9) location(_7998, _8000) ? creep
Exit: (9) location(computer, office) ? creep
Call: (9) door(kitchen, office) ? creep
Exit: (9) door(kitchen, office) ? creep
X = computer,
Y = office ;
Redo: (9) door(kitchen, office) ? creep <==== 3
Fail: (9) door(kitchen, office) ? creep
false.
Я понимаю, как работает привязка переменных, но я не понимаю, почему Prolog возвращает
Redo: (9) door(kitchen, office) ? creep
<==== 1 Redo: (9) door(kitchen, office) ? creep
<==== 3
после нахождения первого решения (и того же самого для последнего решения),
в то время как он сразу ищет новое связывание X и Y после второго решения
Redo: (9) location(_7998, _8000) ? creep
<==== 2
Почему он не сразу продолжает искать новое связывание X и Y после первого и последнего решения, вместо того чтобы прибегать к
Redo: (9) door(kitchen, office) ? creep
<==== 3
(что все равно не получается)?
(Я нашел подобный вопрос здесь, но, к сожалению, моя репутация не позволяет мне комментировать там, и я думаю, что эта конкретная проблема не имеет отношения к моей версии Prolog (как я пробовал с SWI-Prolog и GNUProlog))
Заранее спасибо за предложение любой ясности.
2 ответа
Этот ответ использует SWI-Prolog.
Первое, что может помочь при первом использовании trace, - это сделать все порты видимыми. По умолчанию порт унификации не виден, но его можно сделать видимым с помощью
?- visible(+unify).
Теперь, поскольку это такой короткий запрос, вместо того, чтобы нажимать клавишу пробела для каждого порта, мы можем отключить привязку привязанных портов с помощью
?- leash(-call).
?- leash(-exit).
?- leash(-redo).
?- leash(-fail).
Теперь, если вы включите трассировку и запустите запрос
?- trace.
[trace] ?- (location(X,Y),door(kitchen,Y)).
вам не придется нажимать пробел, ожидайте ответов.
Сделав так вернется
Call: (9) location(_9632, _9634)
Unify: (9) location(desk, office)
Exit: (9) location(desk, office)
Call: (9) door(kitchen, office)
Unify: (9) door(kitchen, office)
Exit: (9) door(kitchen, office)
X = desk,
Y = office ;
Redo: (9) door(kitchen, office)
Fail: (9) door(kitchen, office)
Redo: (9) location(_9632, _9634)
Unify: (9) location(apple, kitchen)
Exit: (9) location(apple, kitchen)
Call: (9) door(kitchen, kitchen)
Fail: (9) door(kitchen, kitchen)
Redo: (9) location(_9632, _9634)
Unify: (9) location(flashlight, desk)
Exit: (9) location(flashlight, desk)
Call: (9) door(kitchen, desk)
Fail: (9) door(kitchen, desk)
Redo: (9) location(_9632, _9634)
Unify: (9) location('washing machine', cellar)
Exit: (9) location('washing machine', cellar)
Call: (9) door(kitchen, cellar)
Unify: (9) door(kitchen, cellar)
Exit: (9) door(kitchen, cellar)
X = 'washing machine',
Y = cellar ;
Redo: (9) location(_9632, _9634)
Unify: (9) location(nani, 'washing machine')
Exit: (9) location(nani, 'washing machine')
Call: (9) door(kitchen, 'washing machine')
Fail: (9) door(kitchen, 'washing machine')
Redo: (9) location(_9632, _9634)
Unify: (9) location(broccoli, kitchen)
Exit: (9) location(broccoli, kitchen)
Call: (9) door(kitchen, kitchen)
Fail: (9) door(kitchen, kitchen)
Redo: (9) location(_9632, _9634)
Unify: (9) location(crackers, kitchen)
Exit: (9) location(crackers, kitchen)
Call: (9) door(kitchen, kitchen)
Fail: (9) door(kitchen, kitchen)
Redo: (9) location(_9632, _9634)
Unify: (9) location(computer, office)
Exit: (9) location(computer, office)
Call: (9) door(kitchen, office)
Unify: (9) door(kitchen, office)
Exit: (9) door(kitchen, office)
X = computer,
Y = office ;
Redo: (9) door(kitchen, office)
Fail: (9) door(kitchen, office)
false.
который теперь имеет видимые порты Unify.
Поскольку это такой короткий запрос, я прокомментирую важные строки трассировки, и это, в свою очередь, должно ответить на ваши вопросы.
% location fact 1: location(desk, office) -------------------------
% First predicate of query - location(X,Y)
% The location facts are matched in the order of the source code
% Since the code is looking for location(X,Y)
% it matches location fact 1: location(desk, office)
% Since there are more location facts like location(X, Y),
% e.g.
% location(apple,kitchen).
% location(flashlight,desk).
% location('washing machine',cellar).
% location(nani,'washing machine').
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
% a choice point is generated
% choice point: location 1
Call: (9) location(_9632, _9634)
% Unifies with first location fact.
% X binds with desk
% Y binds with office
Unify: (9) location(desk, office)
Exit: (9) location(desk, office)
% Second predicate of query - door(kitchen,Y)).
% Y is bound with office
% The door facts are matched in the order of the source code
% Since the code is only looking for door(kitchen,office)
% it matches door fact 2: door(kitchen,office)
% Since there are more door facts like door(kitchen,Y),
% e.g.
% door(kitchen,cellar).
% a choice point is generated
% choice point: door 1
Call: (9) door(kitchen, office)
% Since there is a door(kitchen, office) fact
% unify with second predicate
Unify: (9) door(kitchen, office)
Exit: (9) door(kitchen, office)
% No more predicates in the query so return result.
X = desk,
Y = office ;
% Remember choice point: door 1
% Use the second predicate
% on the remaining door facts like door(kitchen,Y)
% e.g.
% door(kitchen,cellar).
Redo: (9) door(kitchen, office)
% There are no more door facts that unify with door(kitchen, office)
% so fail.
Fail: (9) door(kitchen, office)
% Since the second predicate failed,
% go back to the first predicate location(X,Y)
% location fact 2: location(apple, kitchen) -----------------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(apple,kitchen).
% location(flashlight,desk).
% location('washing machine',cellar).
% location(nani,'washing machine').
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
% The second fact unifies with the first predicate location(X,Y)
% X binds with apple
% Y binds with kitchen
Unify: (9) location(apple, kitchen)
Exit: (9) location(apple, kitchen)
% Second predicate of query - door(kitchen,Y)).
% Y is bound with kitchen
% The door facts are matched in the order of the source code
% Since the code is only looking for door(kitchen,kitchen)
% it matches none of the door facts
% and since it checked all of the door facts
% no choice point was generated.
Call: (9) door(kitchen, kitchen)
% There is no door(kitchen, kitchen) fact so fail.
Fail: (9) door(kitchen, kitchen)
% location fact 3: location(flashlight, desk) ---------------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(flashlight,desk).
% location('washing machine',cellar).
% location(nani,'washing machine').
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
Unify: (9) location(flashlight, desk)
Exit: (9) location(flashlight, desk)
Call: (9) door(kitchen, desk)
Fail: (9) door(kitchen, desk)
% Since the second predicate failed,
% go back to the first predicate location(X,Y)
% location fact 4: location('washing machine', cellar) -----------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location('washing machine',cellar).
% location(nani,'washing machine').
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
% The forth fact unifies with the first predicate location(X,Y)
% X binds with 'washing machine'
% Y binds with cellar
Unify: (9) location('washing machine', cellar)
Exit: (9) location('washing machine', cellar)
% Second predicate of query - door(kitchen,Y)).
% Y is bound with cellar
% The door facts are matched in the order of the source code
% Since the code is only looking for door(kitchen,cellar)
% it matches door fact 4: door(kitchen,cellar)
% Since there are NO more door facts like door(kitchen,Y),
% NO choice point is generated
Call: (9) door(kitchen, cellar)
% There is a door(kitchen, cellar) fact so unify.
Unify: (9) door(kitchen, cellar)
Exit: (9) door(kitchen, cellar)
% No more predicates in the query so return result.
X = 'washing machine',
Y = cellar ;
% location fact 5: location(nani, 'washing machine') --------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(nani,'washing machine').
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
Unify: (9) location(nani, 'washing machine')
Exit: (9) location(nani, 'washing machine')
Call: (9) door(kitchen, 'washing machine')
Fail: (9) door(kitchen, 'washing machine')
% location fact 6: location(broccoli, kitchen) --------------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(broccoli,kitchen).
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
Unify: (9) location(broccoli, kitchen)
Exit: (9) location(broccoli, kitchen)
Call: (9) door(kitchen, kitchen)
Fail: (9) door(kitchen, kitchen)
% location fact 7: location(crackers, kitchen) --------------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(crackers,kitchen).
% location(computer,office).
Redo: (9) location(_9632, _9634)
Unify: (9) location(crackers, kitchen)
Exit: (9) location(crackers, kitchen)
Call: (9) door(kitchen, kitchen)
Fail: (9) door(kitchen, kitchen)
% Since the second predicate failed,
% go back to the first predicate location(X,Y)
% location fact 8: location(computer, office) ---------------------
% Remember choice point: location 1
% Use the first predicate
% on the remaining location facts like location(X,Y)
% e.g.
% location(computer,office).
Redo: (9) location(_9632, _9634)
% The last fact unifies with the first predicate location(X,Y)
% X binds with computer
% Y binds with office
Unify: (9) location(computer, office)
Exit: (9) location(computer, office)
% Second predicate of query - door(kitchen,Y)).
% Y is bound with office
% The door facts are matched in the order of the source code
% Since the code is only looking for door(kitchen,office)
% it matches door fact 2: door(kitchen,office)
% Since there are more door facts like door(kitchen,Y),
% e.g.
% door(kitchen,cellar).
% a choice point is generated
% choice point: door 2
Call: (9) door(kitchen, office)
% Since there is a door(kitchen, office) fact
% unify with second predicate
Unify: (9) door(kitchen, office)
Exit: (9) door(kitchen, office)
% No more predicates in the query so return result.
X = computer,
Y = office ;
% Remember choice point: door 2
% Use the second predicate
% on the remaining door facts like door(kitchen,Y)
% e.g.
% door(kitchen,cellar).
Redo: (9) door(kitchen, office)
% There are no more door facts that unify with door(kitchen, office)
% so fail.
Fail: (9) door(kitchen, office)
% There are no more location facts so end the query.
false.
дополнение
Когда я создавал ответ, он находился в текстовом редакторе, который может выделить синтаксис для кода Пролога, и чтобы помочь мне разобраться, у меня было три открытых панели для сравнения. На одной панели было расположение и правила дверей. На одной панели был комментарий, а на третьей - аналогичный комментарий. По мере продвижения по коду я продолжал обновлять комментарии на третьей панели, чтобы они соответствовали аналогичным комментариям на второй панели, одновременно проверяя факты на первой панели. Я отмечаю это, потому что это, вероятно, лучший способ понять комментарии, чем читать их из этого ответа в опубликованном виде.
Редактор - Visual Studio Code, и для выделения Prolog установлено расширение Prolog.
Это просто комментарий, опубликованный как ответ, потому что у него есть картинка.
Если вы используете графический отладчик, вы можете видеть, когда создаются точки выбора.
?- gtrace.
true.
[trace] ?- (location(X,Y),door(kitchen,Y)).
На следующем изображении отладчика я выделил точку выбора зеленым прямоугольником.
Для выхода из режима трассировки на верхнем уровне введите nodebug
,
[trace] ?- nodebug.
true.
?-
Примечание: это точки выбора, которые приводят к использованию порта повтора.
Примечание. Другой способ отладки пролога - использование фрагмента сбоя. Также прочитайте вопросы, помеченные срезом