количестве различных типов фигур. Мы будем вынуждены заранее предвидеть все возможные типы, которые могут когда-либо встретиться. Придется заготовить по предложению на каждый тип, хотя во всех этих предложениях по существу говорится одно и то же: возьми параметры исходной фигуры, умножь их на коэффициент и создай фигуру того же типа с этими новыми параметрами.
Ниже приводится программа, в которой делается попытка (неудачная) справиться для начала хотя бы со всеми однопараметрическими фигурами при помощи одного предложения:
увел( Тип( Пар), F, Тип( Пар1) ):-
Пар1 is F*Пар.
Однако в Прологе подобные конструкции, как правило, запрещены, поскольку функтор должен быть атомом, и, следовательно, переменная Тип
синтаксически не будет воспринята как функтор. Правильный метод — воспользоваться предикатом '=..
'. Тогда процедура увел
будет иметь обобщенную формулировку, пригодную для фигур любых типов:
увел( Фиг, F, Фиг1):-
Фиг =.. [Тип | Параметры],
умножспис( Параметры, F, Параметры1),
Фиг1 =.. [Тип | Параметры)].
умножспис( [], _, []).
умножспис( [X | L], F, [X1 | L1] ) :-
X1 is F*X, умножспис( L, F, L1).
Наш следующий пример использования предиката '=..
' связан с обработкой символьных выражений (формул), где часто приходится подставлять вместо некоторого подвыражения другое выражение. Мы определим отношение
подставить( Подтерм, Терм, Подтерм1, Терм1)
следующим образом: если все вхождения Подтерм
'а в Терм
заменить на Подтерм1
, то получится Терм1
. Например:
?- подставить( sin( x), 2*sin( x)*f( sin( x)), t, F ).
F = 2*t*f( t)
Под 'вхождением' Подтерм
'а в Терм
мы будем понимать такой элемент Терм
'а, который Подтерм
'ом. Вхождения будем искать сверху вниз. Поэтому цель
?- подставить( а+b, f( а, А+В), v, F).
даст результат
F = f( а, v)
А = а
В = b
а не
F = f( a, v + v)
А = а + b
В = а + b
При определении отношения подставить
нам нужно рассмотреть несколько случаев и для каждого принять свое решение:
если Подтерм
= Терм
, то Терм1
= Подтерм1
;
иначе если Терм
— 'атомарный' (не структура),
то Терм1
= Терм
(подставлять нечего),
иначе подстановку нужно выполнить над аргументами Tерм
'a.
Эти правила можно превратить в программу, показанную на рис. 7.3.
Термы, полученные при помощи предиката '=..
', разумеется, можно использовать и в качестве целей. Это дает возможность программе в процессе вычислений самой порождать и вычислять цели, структура которых не обязательно была известна заранее в момент написания программы. Последовательность целей, иллюстрирующая этот прием, могла бы выглядеть примерно так:
получить( Функтор),
вычислить( Списарг),
Цель =.. [Функтор | Списарг],
Цель
Здесь получить
и вычислить
— некоторые определенные пользователем процедуры, предназначенные для вычисления компонент цели. После этого цель порождается предикатом '=..
', а затем активизируется при помощи простого указания ее имени Цель
.
% Отношение
%
% подставить( Подтерм, Терм, Подтерм1, Терм1)
%
% состоит в следующем: если все вхождения Подтерм'а в Терм
% заменить на Подтерм1, то получится Терм1.
% Случай 1: Заменить весь терм
подставить( Терм, Терм, Терм1, Терм1) :- !.
% Случай 2: нечего подставлять
подставить( _, Терм, _, Терм) :-
atomic( Терм), !.
% Случай 3: Проделать подстановку в аргументах
подставить( Под, Терм, Под1, Терм1) :-
Терм =.. [F | Арги],
% Выделить аргументы
подспис( Под, Арги, Под1, Арги1),
% Выполнить над ними подстановку
Терм1 =.. [F | Арги1].
подспис( Под, [Терм | Термы], Под1, [Терм1 | Термы1]) :-
подставить( Под, Терм, Под1, Терм1),
подспис( Под, Термы, Под1, Термы1).
Рис. 7.3. Процедура подстановки в терм вместо одного из его подтермов некоторого другого подтерма.
Некоторые реализации Пролога могут содержать требование, чтобы все цели, появляющиеся в программе, по своей call
(вызов), чьим аргументом является цель, подлежащая вычислению. В соответствий с этим предыдущий пример должен быть переписан так:
...
Цель = [Функтор | Списарг],
саll( Цель)