Структуры
В соответствии с теорией предикатов первого порядка единственная структура данных в логических программах - термы. Определение термов индуктивно. Константы и переменные являются термами. Кроме того, термами являются составные термы, или структуры. Составной терм содержит функтор (называемый главным функтором терма) и последовательность из одного или более аргументов, являющихся термами. Функтор
задается своим функциональным именем, которое суть атом, и своей арностью
(местностью), или числом аргументов. Синтаксически составные термы имеют вид f(t1,t2,...,tn), где f - имя n-арного функтора, а ti - аргументы. Геометрически мы можем рассматривать термы как деревья, где для составного терма корнем является главный функтор терма, а поддеревьями - его аргументы.
Поскольку предикаты синтаксически выглядят так же, как составные термы (роль функтора играет предикатный символ), то, следовательно, программы и данные в Прологе имеют одинаковую форму (как в Лиспе).
В Пролог-программах допускается использование одного и того же предикатного (или функционального символа) с разным числом аргументов. Это возможно, поскольку каждый функтор определяется двумя параметрами: именем и арностью.
Некоторые функциональные символы являются встроенными: например, знаки арифметических операций. Поэтому арифметические выражения, рассмотренные ранее, являются примером составных термов (структур), записанных в инфиксной форме. Но их можно записывать и в префиксной форме.
Примеры:
?- X is *(+(5,4),+(5,8)).
X = 117
Yes
?- X = *(+(5,4),+(5,8)).
X = (5 + 4) * (5 + 8)
Yes
Структуры используются в Прологе для конструирования сложных типов данных. Например, для представления даты естественно использовать терм вида ‘дата’(1,’май’,1998).
Проверка типа терма
Для проверки типа терма используются встроенные предикаты.
var(+Term) - свободная переменная
nonvar(+Term) - несвободная (конкретизированная) переменная
integer(+Term) - целое число
float(+Term) - вещественное число
number(+Term) - целое или вещественное число
atom(+Term) - атом
atomic(+Term) - атом или число
ground(+Term) -терм не содержит свободных переменных
Если не var(X) и не atomic(X), то X - структура.
Рекурсивные структуры
Рассмотрим использование рекурсивных структур при представлении простых электрических цепей. Пусть цепи содержат только резисторы, соединенные последовательно или параллельно.
Цепь, состоящую из одного резистора, будем представлять числом - номиналом резистора. Два резистора R1 и R2, соединенные последовательно, обозначим термом succ(R1,R2), а параллельно - термом para(R1,R2). Используя эти обозначения рекурсивно, мы можем определить произвольные цепи, состоящие только из последовательно и параллельно соединенных сопротивлений. Например, цепь из 4 резисторов:
para(1.0,succ(para(2.0,3.0),4.0)).
Упрощение цепей
simple(X,X):-
number(X).
simple(succ(X,Y),Z):-
simple(X,R1),
simple(Y,R2),
Z is R1+R2.
simple(para(X,Y),Z):-
simple(X,R1),
simple(Y,R2),
Z is (R1*R2)/(R1+R2).
?- simple(para(1.0,succ(para(2.0,3.0),4.0)),X).
X = 0.838710
Yes
Бинарные деревья
Бинарные деревья задаются с помощью тернарного функтора tree(Left,Root,Right), где Root - элемент, находящийся в вершине, а Left и Right - соответственно левое и правое поддерево. Пустое дерево изображается атомом nil. Следующий терм является примером более сложного дерева tree(nil, 5, tree(nil, 6, tree(tree(nil, 8, nil), 10, nil))).
% tree_member(+Element,+Tree)
% Отношение выполнено, если элемент является одной из вершин дерева
tree_member(X,tree(_,X,_)).
tree_member(X,tree(Left,_,_)):-
tree_member(X,Left).
tree_member(X,tree(_,_,Right)):-
tree_member(X,Right).