logo search
TurboProlog / Документация / TOM_2

Унификация статических и действительных термов

В данном разделе мы собираемся рассмотреть предикат unify_term, фак-

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

статические термы, действительные термы, а также среду, а на выходе дает

принятую в Прологе унификацию двух различных типов термов, отображаемых

посредством создания переменных, помещаемых в среду.

Предикат unify_term действует совместно с предикатом unify_terml,

который просто вызывает unify_term для каждого элемента списка аргументов

унифицируемого терма. Объявления и определения unify_term и unify_terml

выглядят так:

predicate

determ unify_term(aTerm,sTerm,env)

determ unify_terml(aTermList,sTermList,env)

clauses

unify_terml([],[],_):-!.

unify_terml([ATerm1|ATL1],[STerm2|STL2],Env):-

unify_term(ATerm1,STerm2,Env),unify_terml(ATL1,STL2,Env).

unify_term(ATerm,var(ID),Env):-

free(ID),free(ATerm),!,

createVar(ATerm,Env,ID).

unify_term(_,STerm,_):-

bound(STerm),

Sterm=var("_"),!.

unify_term(ATerm,var(ID),Env):-

bound(ID),!,

member(e(ID,ATerm1),Env),

ATerm1=ATerm.

unify_term(int(I),int(I),_):-!.

unify_term(atom(A),atom(A),_):-!.

unify_term(str(S),str(S),_):-!.

unify_term(char(C),char(C),_):-!.

unify_term(list(H1,T1),list(H2,T2),Env):-!,

unify_term(H1,H2,Env),

unify_term(T1,T2,Env).

unify_term(nill,nill,_):-!.

unify_term(cmp(ID,L1),cmp(ID,L2),Env):-!,

unify_terml(L1,L2,Env).

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

потому что они предназначены для специальных действий с переменными и

средой в некоторых конкретных условиях, что иногда также влечет за собой

иной потоковый шаблон.

Второе предложение unify_term обрабатывает пустую унификацию с ано-

нимными переменными, что может быть использовано интерпретатором правил

(мы обсудим это дальше).

Третье предложение для unify_term создает aTerm (активный терм) и

устанавливает среду для переменных в списке аргументов.

Четвертое предложение для unify_term отвечает за создание трех ак-

тивных термов в среде и проверку на стандартное унификационное равенство

в случае наличия обоих термов.

unify_term(АTerm, var(ID), Env):- /* (aTerm, sTerm, среда)*/

bound(ID),! /* удостовериться, что ID существует */

member(e(ID, АTerml), Env), /* обновляет ID и Terml в среде*/

АTerml = АTerm /*унифицирует aTerm со значением в среде ID*/

Проверка на установку ID сделана для того, чтобы избежать активации

предложения для потокового шаблона, где sTerm является аргуменом вывода,

в этом случае он частично связан с var(_) (это подробно объяснено далее).

Когда вызывается предикат member, то он или связывает АTerm1 с пере-

менной, идентефицируемой ID или, если в среде еще нет ID, member добавит

его и вернет АTerm1 несвязанным. После этого унификация двух термов

(АTerm и АTerm1) происходит одним из трех способов:

1. Если оба терма связаны, то унификация двух термов заканчива-

ется успешно или нет (это зависит от их значений).

2. Если связан только один терм, то унификация произойдет путем

установки двух термов друг на друга.

3. Если оба терма являются свободными переменными, то они раз-

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

и каждый указатель будет указывать на один и тот же свободны

адрес).

Вот несколько целей, показывающих, как происходит связывание пере-

менных в среде:

Способ, каким вызывается предикат member, очень важен. Он показыва-

ет, как легко, не думая об аргументах потока, можно создать хаос. Вместо

такого предложения, как

unify_term(АTerm, var(ID), Env):-bound(ID),!

member(e(ID, АTerml), Env),

АTerml = АTerm

вы может захотеться воспользоваться

unify_term(АTerm, var(ID), Env):-bound(ID),!

member(e(ID, АTerml), Env).

надеясь, что традиционное сопоставление заголовков, принятое в Прологе,

сделает то, что последующая унификация (АTerml = АTerm) делает в исходном

вызове. Однако, если вы внимательнее отнесетесь к определению предиката

member

member(X, [X|_]):-!.

member(X, [_|L]):-member(X,L).

то увидите, что вызов member(e(ID, АTerml), Env). никогда не приведет к

неуспеху, даже в случае различных термов. Вместо этого, member создаст

два элемента в среде, имеющих два различных значения для одной и той же

переменной. Например, если такой элемент уже был в среде:

e("X", int(<некоторое_значение>))

и у вас было member(e("X", ATerm, Env), где АTerm = другое_значение. то

member добавит новый элемент для "Х", и среда будет выглядеть так:

e("X", int(<некоторое_значение>))

e("X", int(<другое_значение>))

Вот цель, показывающая данную ситуацию:

Goal: Env=(e("x", int(0))|_]

member=(e("x", int(1)), Env)

Env=(e("x", int(0)), e("x", int(1))|_]

1 Solution

Почему для каждого функтора требуются отдельные предложения (тип ар-

гумента?). Функторам сложных объектов в Турбо Прологе присваиваются одно-

байтные значения, повышающие эффективность использования памяти и увели-

чивающие скорость, поэтому, хотя "int" и "int" одинаково выглядят в пра-

виле unify_term(int(I), int (I),_):-..., но они относятся к различным об-

ластям (соответственно aTerm и sTerm). Они могут корректно быть установ-

лены друг на друга.

Обратите внимание, что многие базы правил не включают понятие иден-

тефикаторов как отдельного типа данных и редко используют списки. В край-

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

ветствующие предложения для unify_term), которые используются в конкрет-

ной прикладной задаче.