Изображения кода Пролога, которые вы разместили, показывают какой-то необычный или очень старый Пролог, в частности, для списка использование [H:T]
теперь выполняется как [H|T]
, обратите внимание на изменение с :
на |
, и<=
чаще встречается как :-
.
Чтобы понять код Пролога, легче начать снизу вверх.Я не буду описывать унификацию или обратную цепочку , поскольку для перехода на этот уровень детализации здесь потребуются главы, стоящие здесь.
Первый предикат, который нужно понять, это Append / 3 .Обычно вы никогда не видите код для добавления, указанный как встроенный предикат, но здесь он предоставляется.
Append / 3 имеет три параметра, которые являются списком.Первые два добавляются вместе, чтобы сформировать третий.
?- append_01([],[],R).
R = [].
?- append_01([a],[],R).
R = [a].
?- append_01([],[a],R).
R = [a].
?- append_01([a],[b],R).
R = [a, b].
, но предикаты Prolog могут иметь другие операции режимов , которые могут привязывать значения к тому, что будет считаться входными параметрами в других языках программирования.Например,
?- append(X,[b],[a,b]).
X = [a] ;
false.
?- append_01([a],Y,[a,b]).
Y = [b].
?- append(X,Y,[a,b]).
X = [] , Y = [a, b] ;
X = [a] , Y = [b] ;
X = [a, b], Y = [] ;
false.
или может быть просто использован для проверки аргументов
?- append([a],[b],[a,b]).
true.
?- append([a],[c],[a,b]).
false.
Далее следует предикат обратный / 2, который в Прологе более известен как reverse / 2, и снова здесь приводится исходный код.
Это просто берет один список и переворачивает его, например,
?- inverse([],X).
X = [].
?- inverse([a],X).
X = [a].
?- inverse([a,b],X).
X = [b, a].
, однако эта версия исходного кода не очень хорошо работает вдругие режимы, например
?- inverse(X,[]).
X = [] ;
Action (h for help) ? abort
% Execution Aborted
, но это не имеет значения, чтобы ответить на вопрос.
Следующая часть того, что вы опубликовали, - это след выполнения запроса
?- inverse([[1,2,3],[5,4]],A).
Чтобы использовать трассировку в вашем коде, так как есть встроенный предикат для append / 3, мне пришлось переименовать предикат.Вот код, который я использовал.
inverse([],[]).
inverse([H|T],D) :-
inverse(T,Z),
append_01(Z,[H],D).
append_01([],X,X).
append_01([X|L],M,[X|N]) :-
append_01(L,M,N).
Использование SWI-Prolog
настройка трассы
?- visible(+all),leash(-all).
запуск трассировки
trace.
выполнить запрос
[trace] ?- inverse([[1,2,3],[5,4]],A).
возвращает
Call: (8) inverse([[1, 2, 3], [5, 4]], _7548)
Unify: (8) inverse([[1, 2, 3], [5, 4]], _7548)
Call: (9) inverse([[5, 4]], _7794)
Unify: (9) inverse([[5, 4]], _7794)
Call: (10) inverse([], _7794)
Unify: (10) inverse([], [])
Exit: (10) inverse([], [])
Call: (10) append_01([], [[5, 4]], _7802)
Unify: (10) append_01([], [[5, 4]], [[5, 4]])
Exit: (10) append_01([], [[5, 4]], [[5, 4]])
Exit: (9) inverse([[5, 4]], [[5, 4]])
Call: (9) append_01([[5, 4]], [[1, 2, 3]], _7548)
Unify: (9) append_01([[5, 4]], [[1, 2, 3]], [[5, 4]|_7792])
Call: (10) append_01([], [[1, 2, 3]], _7792)
Unify: (10) append_01([], [[1, 2, 3]], [[1, 2, 3]])
Exit: (10) append_01([], [[1, 2, 3]], [[1, 2, 3]])
Exit: (9) append_01([[5, 4]], [[1, 2, 3]], [[5, 4], [1, 2, 3]])
Exit: (8) inverse([[1, 2, 3], [5, 4]], [[5, 4], [1, 2, 3]])
A = [[5, 4], [1, 2, 3]].
Я не буду объяснять детали трассировки, поскольку другие SO Q & A делают , что .
Трасса, которую вы опубликовали, также содержит больше деталей, чем сгенерированная с помощью trace
, например, привязок (θ).
Чтобы увидеть привязки, используйте gtrace /0
?- gtrace.
% The graphical front-end will be used for subsequent tracing
true.
, затем выполните запрос
[trace]?- inverse([[1,2,3],[5,4]],A).
и нажмите пробел, чтобы перейти на один шаг.Вам придется экспериментировать с ним, чтобы узнать, как он работает;AFAIK нет опубликованной документации о том, как его использовать.
Из комментария OP:
Есть некоторые замены букв и цифр и тета-символа, которые делаютМне трудно понять.
Хотя привязки (θ) более специфичны для логических языков , числа также встречаются в стековых функциональных языках ,см. индекс Де Брюина .Кроме того, вместо написания привязок с использованием вертикального разделителя строк (---), я предпочитаю использовать (as), как показано здесь .
Строки 1 -4 являются только указанным исходным кодомснова.
Обычно при трассировке цель состоит в том, чтобы отобразить древовидную структуру выполнений (вызовов), но с этими строками, если вы не знаете, как работает Пролог, действительно трудно понять, что существует древовидная структура.
Строки с чертами надписи предназначены для того, чтобы помочь понять, что происходит, но если вы просто следите за ходом выполнения (вызовов), то вы можете обнаружить, что, как и я, они просто вызывают путаницу и могутбыть проигнорированным.
На что вы отметили в комментариях Res(_,_)
относится к предыдущим строкам трассировки.Таким образом, Res (5,2) в строке 6 можно прочитать, так как строка 6 является результатом вызова из строки 5 и затем вызывает строку 2.
Унификации или привязки (θ) отображаются как наборы,Я не совсем уверен, что представляют номера супер и субскриптов, но они явно связаны с индексами Де Брюина.Вам нужно будет попросить своего учителя объяснить супер и вспомогательные сценарии.
После нескольких попыток объяснить это только текстом, я, наконец, прибег к использованию Microsoft Visio, чтобы сделать это в виде графического дерева, которое было намного проще, быстрее и точнее.
Даже если это не было нужно, я добавиллиния трассировки выводится из SWI-Prolog в изображение, а затем помещает только строки вызова в соответствующие места в дереве, так что если вы хотите соотнести их, вы можете.Я сделал это для себя, чтобы проверить, правильно ли это.
Я не удивлюсь, если появятся несколько опечаток, так как мне приходилось много раз переделывать некоторые его части, чтобы их было легко понять.Надеюсь, я достиг этой цели.