Этот набор правил легко написать на Прологе, поскольку мы можем представить арифметические выражения как структуры и использовать знаки операций как функторы этих структур. Кроме того, сопоставление целевого утверждения с заголовком правила мы можем использовать как сопоставление образцов. Рассмотрим цель
d(E,X, F), которая считается согласованной, когда производная выражения
Eпо константе
[12]
Xесть выражение
F. Помимо знаков операций +, -, *, /, которые имеют встроенные определения, нам нужно определить операцию ^, такую, что
X^Yозначаете
?- d(x+1,x,X).
X = 1+0
?- d(x*x-2,x,X).
X = х*1+1*х-0
Заметим, что само по себе простое преобразование одного выражения в другое (на основе правил) не всегда дает результат в приведенной (упрощенной) форме. Приведение результата должно быть записано в виде отдельной процедуры (см. разд. 7.12). Программа дифференцирования состоит из определений дополнительных операций и построчной трансляции приведенных выше правил преобразования в утверждения Пролога:
?- op(10,yfx,^).
?- op(9,fx,~).
d(X,X,1):-!.
d(C,X,0):- atomic(C).
d(~U,X,~A):- d(U,X,A).
d(U+V,X,A+B):- d(U,X,A), d(V,X,B).
d(U-V,X,A-В):- d(U,X,A), d(V,X,B).
d(C*U,X,C*A):- atomic(C), C\=X, d(U,X,A),!.
d(U*V,X,B*U+A*V):- d(U,X,A), d(V,X,B).
d(U/V,X,A):- d(U*V^~1),X,A).
d(U^C,X,C*U^(C-1)*W):- atomic(C),C\=X,d(U,X,W).
d(log(U),X,A*U^(~1)):- d(U,X,A).
Обратите внимание на два места, в которых задан предикат отсечения. В первом случае отсечение обеспечивает тот факт, что производная от переменной по ней самой распознается только первым утверждением, исключая возможность применения второго утверждения. Во втором случае предусмотрено два утверждения для умножения. Первое – для специального случая. Если имеет место специальный случай, то утверждение для общего случая должно быть устранено из рассмотрения.
Как уже говорилось, данная программа выдает решения в неприведенной форме (т. е. без упрощений). Например, всякое вхождение х*1может быть приведено к х, а всякое вхождение вида х*1+1*х-0может быть приведено к 2*х. В следующем разделе рассматривается программа алгебраических преобразований, которую можно использовать для упрощения арифметических выражений. Примененный способ очень похож на тот, каким выше выводились производные.
7.12. Отображение структур и преобразование деревьев
Если некоторая структура покомпонентно копируется с целью образования новой структуры, то мы говорим, что одна структура
преобразовать([],[]).
преобразовать([А|В],[С|D]):- заменить(А,С),преобразовать(В,D).
Поскольку отображение имеет довольно широкое применение, мы можем определить предикат отобспистакой, что целевое утверждение отобспис(Р, L, M)согласуется с базой данных, применяя предикат Рк каждому элементу списка Lи образуя в результате новый список М. При этом предполагается, что предикат Римеет два аргумента: первый аргумент для передачи «входного» элемента, а второй аргумент – для измененного элемента, подлежащего включению в список М.
отобспис((_,[],[]).
отобспис((P,[X|L],[Y|M]):- Q =..[P,X,Y],call(Q),отобспис(Р,L,М).
Об этом определении следует сказать несколько слов. Во-первых, определение содержит граничное условие (первое утверждение) и общий рекурсивный случай (второе утверждение). Во втором утверждении используется оператор '=..', формирующий целевое утверждение на основе предиката (Р), входного элемента (X)и переменной (Y), которую предикат Рдолжен конкретизировать, чтобы образовать измененный элемент. Затем делается попытка согласовать цель Q, в результате чего Yконкретизируется, образуя голову третьего аргумента данного вызова предиката отобспис. Наконец, рекурсивный вызов отображает хвост первого аргумента в хвост второго.
Функции предиката преобразоватьможет выполнять предикат отобспис. Полагая, что предикат заменитьопределен как в гл. 3, такое использование отобсписмогло бы выглядеть следующим образом:
?- отобспис(заменить,[уоu,аrе,а,computer],Z).
Z = [i, [am, not], a, computer]