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

Выполнение выполняемых термов: предикат call.

Предикат call отвечает за окончательное выполнение подцелей, опреде-

ленных unify_body. call также отвечает за распознание и выполнение тех

встроенных предикатов, которые должен иметь интерпретатор.

call объявляется так:

nondeterm call(string, aTermList)

Минимальная конфигурация включает только два предложения call:

call("true",[]):-!.

call(ID, ATermList):-

getbacktrack(Btop),

clause(cmp(ID, STermList1), Body),

free(Env),

unify_terml(ATermList, STermList1, Env),

unify_body(Body, Env, Btop).

Мы считаем, что все правила хранятся как sTerm в предикате базы дан-

ных, называемом clause, со своими заголовками и телами в двух различных

предикатах, например:

greet :- write("Hello there"), nl.

представлен статическим термом

cmp(":-",[atom("greet"), cmp(",",[cmp("write", ...])])

Однако этот sTerm хранится без ":-", вот так:

clause(cmp("greet", []),

cmp(",", [cmp("write", [str("Hello there")]), atom("nl")]))

Первое предложение для clause выполняется для фактов (предложений

без тела). Из соображений общности они хранятся в предикате clause с те-

лом, состоящим из одного атома true, например: clause(Head, atom(true)).

Второе предложение для clause отвечает за выполнение определенных

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

создается новая среда для предложения, которое надо выполнить

(free(Env)). Все, что должно войти в это предложение с помощью аргументов

будет доступно в аргументе ATermList и будет включено в эту среду вызовом

unify_terml. Вызов unify_terml может не удасться, если аргументы искомого

предложения не совпадают с аргументами, определенными в вызове.

АTermList, входящий во второе предложение call, состоит из термов,

определенных в вызываемом предложении в базе данных. Делается это или

прямо, например:

..., consider(fruit(banana,150), Health_factor), ...

или с помощью переменных, вот так:

..., Name=banana, Fondness=150, consider(fruit(Name,Fondness),

Health_factor),

...

В обоих случаях АTermList будет

[cmp("fruit",[atom("banana"), int(150)]),_]

где знак (_) означает свободную переменную для Health_factor.

Предположим у вас есть следующие предложения для consider:

consider(meat(burger,_):- !, fail.

consider(meat(Name,Fond), OK):- ...

consider(vegetable(Name, Fond), OK):- ...

consider(fruit(Name, Fond), OK):- ...

Вы увидете, что попытка объединить действительный список термов

[cmp("fruit", [atom("banana"), int(150)]),_]

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

в случае четвертого предложения (consider(fruit(Name, Fond), OK)).

Остерегайтесь соображений императивного программирования, сосредото-

ченном на какой-то "видимой" внешней активности. Выполняя базу правил, мы

интересуемся выполнением или невыполнением гипотезы, что означает спуск:

- от гипотезы

- через ее подцели

- и их подцели

- и т. д.

- к фактам, имеющим тело, которое true, и, следовательно,

выполнилось в первом предложении.

Если гипотезу нельзя доказать с помощью фактов и правил базы данных,

это в конце концов отразится в невыполнении вызова unify_ body на уровне

гипотезы. Этот выполнение или невыполнение являются единственным выходом

интерпретации базы правил; на такой выход настроена проверка контрольной

программы.

Хотя кажется соблазнительным включить два предложения для Call в

unify_body (также как предполагается, что в интерпретаторе имеются встро-

енные штатные предикаты), но этого следует избегать. Включение Call и

unify_body в одно целое ошибкой не является, но их функции достаточно

различны, что указывает на то, что их лучше разделить.

Это действительно то, что нужно. Мы получили решение с помощью це-

почки обратных рассуждений.

Теперь, прежде чем мы расширим механизм вывода до таких пределов,

что он сможет интерпретировать весь Пролог, рассмотрим включение встроен-

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