Таким способом структура может наращиваться, включая в себя новые элементы. Определите также соответствующее отношение принадлежности.
7.2. Создание и декомпозиция термов: =.., functor, arg, name
Имеются три встроенные предиката для
декомпозиции и синтеза термов:
functor
,
arg
и
=..
. Рассмотрим сначала отношение
=..
, которое записывается как инфиксный оператор. Цель
Терм =.. L
истинна, если L — список, начинающийся с главного функтора терма
Терм
, вслед за которым идут его аргументы. Вот примеры:
?- f( а, b) =.. L.
L = [f, а, b]
?- T =.. [прямоугольник, 3, 5].
T = прямоугольник( 3, 5)
?- Z =.. [p, X, f( X,Y) ].
Z = p( X, f( X,Y) )
Зачем может понадобиться разбирать терм на составляющие компоненты — функтор и его аргументы? Зачем создавать новый терм из заданного функтора и аргументов? Следующий пример показывает, что это действительно нужно.
Рассмотрим программу, которая манипулирует геометрическими фигурами. Фигуры — это квадраты, прямоугольники, треугольники, окружности в т.д. В программе их можно представлять в виде термов, функтор которых указывает на тип фигуры, а аргументы задают ее размеры:
квадрат( Сторона)
треугольник( Сторона1, Сторона2, Сторона3)
окружность( R)
Одной из операций над такими фигурами может быть увеличение. Его можно реализовать в виде трехаргументного отношения
увел( Фиг, Коэффициент, Фиг1)
где
Фиг
и
Фиг1
— геометрические фигуры одного типа (с одним в тем же функтором), причем параметры
Фиг1
равны параметрам
Фиг
, умноженным на
Коэффициент
. Для простоты будем считать, что все параметры
Фиг
, а также
Коэффициент
уже известны, т.е. конкретизированы числами. Один из способов программирования отношения
Такая программа будет работать, однако она будет выглядеть довольно неуклюже при большом количестве различных типов фигур. Мы будем вынуждены заранее предвидеть все возможные типы, которые могут когда-либо встретиться. Придется заготовить по предложению на каждый тип, хотя во всех этих предложениях по существу говорится одно и то же: возьми параметры исходной фигуры, умножь их на коэффициент и создай фигуру того же типа с этими новыми параметрами.
Ниже приводится программа, в
которой делается попытка (неудачная) справиться для начала хотя бы со всеми однопараметрическими фигурами при помощи одного предложения:
увел( Тип( Пар), F, Тип( Пар1) ):-
Пар1 is F*Пар.
Однако в Прологе подобные конструкции, как правило, запрещены, поскольку функтор должен быть атомом, и, следовательно, переменная
Тип
синтаксически не будет воспринята как функтор. Правильный метод — воспользоваться предикатом '
=..
'. Тогда процедура
увел
будет иметь обобщенную формулировку, пригодную для фигур любых типов:
увел( Фиг, F, Фиг1):-
Фиг =.. [Тип | Параметры],
умножспис( Параметры, F, Параметры1),
Фиг1 =.. [Тип | Параметры)].
умножспис( [], _, []).
умножспис( [X | L], F, [X1 | L1] ) :-
X1 is F*X, умножспис( L, F, L1).
Наш следующий пример использования предиката '
=..
' связан с обработкой символьных выражений (формул), где часто приходится подставлять вместо некоторого подвыражения другое выражение. Мы определим отношение
'ом. Вхождения будем искать сверху вниз. Поэтому цель
?- подставить( а+b, f( а, А+В), v, F).
даст результат
F = f( а, v)
А = а
В = b
а не
F = f( a, v + v)
А = а + b
В = а + b
При определении отношения
подставить
нам нужно рассмотреть несколько случаев и для каждого принять свое решение:
если
Подтерм
=
Терм
, то
Терм1
=
Подтерм1
;
иначе если
Терм
— "атомарный" (не структура),
то
Терм1
=
Терм
(подставлять нечего),
иначе подстановку нужно выполнить над аргументами
Tерм
'a.
Эти правила можно превратить в программу, показанную на рис. 7.3.
Термы, полученные при помощи предиката '
=..
', разумеется, можно использовать и в качестве целей. Это дает возможность программе в процессе вычислений самой порождать и вычислять цели, структура которых не обязательно была известна заранее в момент написания программы. Последовательность целей, иллюстрирующая этот прием, могла бы выглядеть примерно так: