Скачиваний:
55
Добавлен:
01.05.2014
Размер:
143 Кб
Скачать
☆

13.2. Программистские трюки

Для каждого языка программирования имеется набор программистских трюков, и Пролог не составляет исключения. Мы приведем несколько полезных трюков для Пролога. Трюками здесь будут предикаты, которые или обрабатывают сопоставления значений переменным, или демонстрируют использование глобальных переключателей.

Интересная особенность предиката not состоит в том. что при его выполнении переменным никогда не сопоставляются значения. Это связано с явным указанием безуспешности вычисления после выполнения цели, что исключает проведение любых сопоставлений. Указанная особенность используется при определении предиката verify (Goal) в программе 13.1. Эгот предикат проверяет, выполнена ли цель Goal, причем проверка не нарушает текущего сопоставления значений переменным, Предикат определяется через двойное отрицание.

verify (Goal)  not not Goal.

Программа 13.1. Проверка цели.

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

Полезным системным предикатом Edinburgh-Пролога является предикат numbervars (Term, N1,N2), последовательно сопоставляющий переменным терма Term строки вида '$VAR'(N), где число N лежит на отрезке от N1 до N2-1. Например, при успешном решении цели numbervars (foo(X,Y),1,N)? переменной Х сопоставляется строка '$VAR'(I), переменной Y строка '$VAR'(2), а переменной N-число 3.

Этот предикат является еще одним примером предиката, анализирующего структуру терма; определение предиката приведено в программе 13.2. Счетчики в программе возрастают, а не убывают, и это позволяет нумеровать переменные слева направо в возрастающем порядке. Чтобы не возникла ошибка, следует обращаться к процедуре numbervars только тогда, когда второму аргументу сопо­ставлено значение.

numbervars('$VAR'(N),N,Nl) 

N1:=N+ 1,

numbervars(Term,Nl,N2)

nonvar (Term), functor (Term, Name, N),

numbervars (0, N, Term, N1, N2).

numbervars (N, N, Term, Nl, Nl).

numbervars(I,N,Term,N1,N3)

I<N,

I1:=I+ 1,

arg(Il, Term, Arg),

numbervars(Arg, Nl, N2),

numbervars(I1, N, Term, N2, N3).

Программа 13.2. Нумерация переменных в терме.

Предикат numbervars позволяет определять металогические предикаты неожиданным образом. Например

ground(Term)  numbervars(Term,0,0).

Этот же предикат можно использовать при определении отношения freeze следующим образом: freeze(X,Term) copy (X,Term), numbervars (Term,0,N). Определение отношения melt мы отложим до гл. 15. В другом полезном примере исполь­зуется как отношение verify, так и отношение number vars. Для обоснования этого примера мы вернемся к обсуждению металогического сравнения термов, начатому,в разд. 10.2.

Предикат = =/2 задает более сильное отношение эквивалентности, чем унифицируемость, т.е. чем предикат =/2. В Прологе существует понятие промежуточной эквивалентности, заимствованное из логики, а именно: два терма эквивалентны, если они являются алфавитными вариантами. Напомним, что два терма являются алфавитными вариантами, если они совпадают с точностью до переименования переменных, т.е. они могут быть сделаны синтаксически идентич­ными путем последовательного изменения имен переменных в одном из термов. Примерами служат пары термов f(X,Y) и f(Y,Z) f(a,X) uf(a,Y) и пара f(X,X) и f(Y,Y).

Предикат variant (TermI,Term2) выполнен, если термы Term] и Тегт2 являются алфавитными вариантами. Определение этого предиката приведено в программе 13.3. Трюк состоит в следующем: сначала с помощью предиката numbervars (программа 13.2) переменным сопоставляются значения, далее проверяется унифицируемость полученных термов, после чего построенные сопоставления отме­няются. Отмена может быть выполнена с помощью программы verify.

Variants (Term 1, Temi2) 

Verify ((numbervars(Terml, 0, N), numbervars(Term2,0,N), Term] == Term2)).

Программа 15.3. Алфавитные варианты.

Три указанных вида сравнения термов: =/2, verify 12 и = = /2 - расположены в строго возрастающем порядке, где унифицируемость является самым слабым и самым общим отношением. Идентичные термы являются алфавитными варианта­ми, а алфавитные варианты унифицируемы. Различие между сравнениями исчезает для основных термов: в этом случае все три сравнения дают один и тот же результат.

Предикат verify может быть также использован для представления термов, содержащих переменные, в удобном для чтения виде. Дело в том, что в процессе работы интерпретатора Пролога переменным назначаются некоторые внутренние имена. Обычно они совершенно невразумительны, что затрудняет чтение результатов, содержащих переменные. Программа 13.4 определяет отношение write_vnames (Term)- вспомогательную процедуру печати, вводящую вместо чисел обычные имена переменных. Предикат lettervars(X), определенный в программе 13.4, заменяет переменные терма Х литерными строками в соответствии с предвари­тельно заданным списком имен.

Другой программистский трюк состоит в моделировании глобальных переменных с помощью предикатов assert и retract. Отношение flag (Name,Value) обеспечивает доступ к текущему значению переключателя, а отношение set flag (Name, Value) задает значение переключателя. Определение предиката set-flag приведено в программе 13.5.

Одно из применений процедур, управляющих переключателями, - порождение в процессе вычислений имен констант. Отметим, однако, что в нашем случае необходимость в такой функции гораздо меньше, чем в других языках программирования. Обычно такие «gensum-функции» применяются для частичного моделирования свойств логических переменных. Изначальное присутствие логических переменных лишает рассматриваемую функцию большинства ее достоинств.

Чаще всего функция "gensum" выполняется следующим образом: к заданному корневому префиксу, например к х, добавляются числовые суффиксы в возрастающей последовательности, например х1, х2.... и т.д. Переключатель используется Для сохранения количества выбранных числовых суффиксов. Предикат gensum (Prefix,Constant), определенный в программе 13.6, сопоставляет аргументу Constant новое имя константы с заданным префиксом.

write_vnames(Term) lettervars(Term), write(Term), fail.

write„vnames(Term).

lettervars(Tenn) 

list_of_variables(Term, Vars),

variable names(Names),

unify _variables(Vars, Names).

list_of_variables(V,[V])  var(V),!

list_of variables (V,[ ]) constant(V),!. list_oi_variables(Term,Vs) 

functor (Term, F, N),

list of_variables(N, Term, Vsl),

flatten (Vsl,Vs). list_of_.variables(N,Term,[VArgs | Vs]) 

N>0,

arg(N,Term,Arg),

list_of_variables(Arg,VArgs),

N1:= N-1,

list_of_variables(Nl ,Term,Vs). list_of_variables(0,Term,[ ]).

unify_variables([V | Vs],[V | Ns]) !, unify_variables(Vs,Ns).

unify variables([V | Vs],Ns) !, unify _variables(Vs,Ns). unify_variables(Vs,Ns). % Исчерпан список переменных или имен

vапаblе_names(['Х','Y,'Z','U',’V',’W',’Х1','Y1’,’Z1','U1','V1',’W1','Х2','Y2','Z2','U2','V2',”W2’,'X3','Y3’,’Z3','U3’,’V3','W3']).

Программа 13.4. Вывод терма с нечисловыми именами переменных.

set_flag (Name, X) 

nonvar(Name),

retract(flag(Name,Val)),!,

asserta(ilag(Name,X)).

set_flag(Name,X) 

nonvar(Name),asserta(flag(Name,X)).

Программа 13.5. Использование глобальных переключателей.

gensum(Prefix,V)

var{V),

atom (Prefix),

old_value( Prefix, N),

Nl := N+1,

set_flag(gensum (Prefix), N 1),

string_concatenate (Prefix, N 1, V),

!.

old_value (Prefix, N) flag(gensum(Prefix),N),!. old_value(Prefix,0).

string_concatenate(X,Y,XY) name(X,Xs),

name(Y.Ys),

append (Xs,Ys,XYs),

name(XY,XYs).

Программа 13.6. Порождение новых cимволов

Соседние файлы в папке 1-13