Почему Prolog объединяет свободную переменную с другой свободной? - PullRequest
1 голос
/ 07 марта 2019
maxmin([X|L], Max, Min) :-
    maxmin(L, X, X, Max, Min),
    !.

maxmin([], CurrentMax, CurrentMin, Max, Min) :-
    Max is CurrentMax,
    Min is CurrentMin,
    !.
maxmin([X|L], CurrentMax, CurrentMin, Max, Min) :-
    CurrentMax2 is max(X, CurrentMax),
    CurrentMin2 is min(X, CurrentMin),
    maxmin(L, CurrentMax2, CurrentMin2, Max, Min).

После выполнения запроса ?- maxmin([2],Max,Min). он вернет Max = Min, Min = 2..

Почему? У меня есть несколько вариантов этого, и ни один из них, кажется, не работает. Как это возможно, что он назначает бесплатную другую бесплатно? Это какой-то материал для отражения в Прологе, о котором я не знаю?

Трассировка также не показывает ничего особенно интересного. А именно, он выходит из Exit: (8) maxmin([2], 2, 2) ? creep, что выглядит для меня отлично. Это произойдет только тогда, когда у меня есть список 1.

Я, очевидно, не понимаю Пролог, но я не могу понять, где я ошибаюсь. Есть указатели?

1 Ответ

3 голосов
/ 07 марта 2019

Как возможно, что он назначает бесплатную для другой бесплатной?

Использование вами слова assigning говорит нам секрет о том, как вы думаете о Прологе.Когда вы видите = в Прологе, это не назначение, а объединение, см .: = / 2 .Пролог работает путем объединения или, более конкретно, синтаксическое объединение .

Если Пролог может объединить две свободные переменные вместе, например A и B, и когда одна из них становится связанной , другая также связанав то же время, поскольку они были объединены ранее.

Хотя это и не совсем точно, другой способ думать об этом - это указатели.

Если вы начинаете с одного указателя, указывающего на A идругой указатель, указывающий на B, которые являются различными местоположениями, и последние находят, что A и B объединены, указатели на A и B будут скорректированы так, чтобы теперь указывать на одно и то же местоположение.Однако местоположение, на которое они указывают, все еще является несвязанным, поскольку ни A, ни B не имеют значения.Если либо A, либо B связаны со значением, то они оба становятся связанными одновременно, поскольку указатели указывают на одно и то же местоположение.

Вот некоторый тестовый код, демонстрирующий подробности.

test_01 :-
    format('A: ~w~n',[A]),
    format('B: ~w~n',[B]),
    A = B,
    format('A: ~w~n',[A]),
    format('B: ~w~n',[B]),
    A = 5,
    format('A: ~w~n',[A]),
    format('B: ~w~n',[B]).

Выполнение этого возвращает следующее.Я добавил комментарии после факта от руки.

?- test_01.
A: _480      % Line 1
B: _486      % Line 2
A: _480      % line 3
B: _480      % line 4
A: 5         % Line 5
B: 5         % Line 6
true.

В строке 1 внутренняя ссылка на переменную A указана как несвязанная переменная: _480
В строке 2 переменная Bвнутренняя ссылка как несвязанная переменная: _486
Обратите внимание, что _480 и _486 представляют две разные несвязанные переменные.
Обратите внимание, что A и B не являются внутренними ссылаясь на то же самое.

Далее код выполняется A = B

, затем

В строке 3 переменная A внутренне обозначается как _480
В строке 4 переменная *На 1064 * внутренне ссылаются как _480

Обратите внимание, что теперь A и B теперь равны внутренним ссылкам: _480.

Далее код выполняется A = 5

В строке 5 переменная A внутренне ссылается на _480, которая теперь связана со значением 5.
В строке 6переменная B внутренне ссылается на _480, которая теперь связана со значением 5.

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

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


Однако в вашем конкретном примере, поскольку Max и Min никогда не объединялись, этотолько то, как SWI-Prolog отображает их

Я провел трассировку вашего примера, чтобы точно увидеть, на что вы обращали внимание.

?- leash(-all),visible(+all),trace.
true.

[trace]  ?- maxmin([2],Max,Min).
   Call: (8) maxmin([2], _4408, _4410)
   Unify: (8) maxmin([2], _4408, _4410)
   Call: (9) maxmin([], 2, 2, _4408, _4410)
   Unify: (9) maxmin([], 2, 2, _4408, _4410)
   Call: (10) _4408 is 2
   Exit: (10) 2 is 2
   Call: (10) _4410 is 2
   Exit: (10) 2 is 2
   Exit: (9) maxmin([], 2, 2, 2, 2)
   Exit: (8) maxmin([2], 2, 2)
Max = Min, Min = 2.

Возможно, SWI-Prolog ведет таблицу значений отображения и что он замечает, что обаMax и Min имеют одинаковое значение, поэтому отображают их таким образом, но я не хочу тратить время на то, чтобы углубиться в код и найти детали.


Это какой-то рефлексионный материал в Прологе, о котором я не знаю?

Я бы не использовал слово Отражение для его описания.


Некоторые тестовые примеры для вашего кода.Я использовал, чтобы убедиться, что ваш код работает, если у вас есть ошибка и вы забыли спросить об этом.

:- begin_tests(maxmin_tests).

maxmin_test_case([1],1,1).
maxmin_test_case([1,2],2,1).
maxmin_test_case([2,1],2,1).
maxmin_test_case([1,2,3],3,1).
maxmin_test_case([3,2,1],3,1).
maxmin_test_case([2,3,1],3,1).
maxmin_test_case([3,1,2],3,1).

test(1,[forall(maxmin_test_case(Input,Expected_max,Expected_min))]) :-
    maxmin(Input,Max,Min),
    assertion( Max == Expected_max ),
    assertion( Min == Expected_min ).

test(2,[fail]) :-
    maxmin([],_,_).

:- end_tests(maxmin_tests).

Пример выполнения

?- run_tests.
% PL-Unit: maxmin_tests ........ done
% All 8 tests passed
true.
...