В качестве условия выступают корректные булевские выражения, включающие типированные параметры шаблона, операторы отношения и логические операторы {and, or, not}. Вместе с тем, условие может включать и произвольные булевские функции и процедуры, возвращающие логические значения, например: isprime, issqr, type, typematch, match и даже patmatch, что позволяет производить рекурсивный структурно-типированный анализ Maple-выражений. Следующий фрагмент иллюстрирует применение процедуры patmatch для структурно-типированного анализа алгебраических выражений:
> patmatch(sqrt(17*Art + 10*Kr), sqrt(a::odd*Art + b::even*Kr), 'h'), h; true, [a = 17, b = 10] > patmatch(10*x^3 + 3*y^2, a::even*x^b::prime + c::odd*y^d::even, 'h'), h; true, [a = 10, b = 3, c = 3, d = 2] > patmatch(sin(3)*x + F(p*y + t*z), a::trig*x + F(b::symbol*y + c::name*z), 'h'), h; true, [a = sin(3), b = p, c = t] > patmatch(sqrt(v)*x - ln(10)*Pi - exp(3), a::sqrt*x + b::atomic + c::realcons, 'h'), h; true, [a = v, c = −ln 10( ) π − e3, b = 0]> patmatch(sqrt(17*Art + 10*Kr), sqrt(a::even*Art + b::prime*Kr), 't'), t; ⇒ false, t > patmatch(sqrt(17*Art + 10*Kr), conditional(sqrt(a::odd*Art + b::even*Kr), a< b^2), 'g'), g; true, [a = 17, b = 10] > patmatch(10*Art + 3*Kr, conditional(a::even*Art + b::odd*Kr, a > b^2 and a + b <= 15 and evalf(a/b) > 3 and a*b < 32), 'h'), h; ⇒ true, [a = 10, b = 3] > patmatch((10*A + 3*K)/(32*S - 52*G), conditional((10*A + b::odd*K)/(c::even*S - 52*G), c/b > 10 and c + b >= 35 and b^3 < c), 'h'), h; ⇒ true, [b = 3, c = 32] > patmatch(57*sin(x)*exp(y) + 52.47*ln(z), conditional(a::anything*exp(y) + b::float*ln(z), b < 57 and _match(a = v*sin(x), x, 'p')), 'h'), h; ⇒ true, [a = 57 sin(x), b = 52.47] |
Из представленных примеров фрагмента достаточно прозрачно прослеживается общий принцип организации анализа выражений на основе patmatch-процедуры как в ее основном формате, так и с использованием уточняющих условий на основе ключевого слова conditional. При этом, следует отметить, что второй формат данного слова используется для определения табличных правил, операторов и функций, и несколько детальнее рассматривается ниже в связи с обсуждением функций пользователя.
Еще на одном функциональном средстве Maple-языка, использующем механизм шаблонов и табличную структуру данных, следует остановиться особо. По вызову процедуры compiletable([Шаблон_1 = Выход_1, …, Шаблон_n = Выход_n])
возвращается специальная СТ-таблица, входами которой являются шаблоны, определяющие некоторые Maple-выражения, а выходами таблицы - результаты соответствующей обработки данных выражений, например интегрирования, дифференцирования и др.
Тогда по вызову процедуры tablelook(<Выражение>, CT) возвращается выход СТ-таблицы, входу которого по шаблону соответствует указанное первым фактическим аргументом выражение. В случае отсутствия в СТ-таблице входа, по шаблону соответствующего выражению, процедурой возвращается FAIL-значение. Модифицировать СТ-таблицу путем добавления в нее новых входов можно посредством insertpattern-процедуры, по которой новые входы помещаются в конец таблицы. При необходимости помещения нового входа в другое место требуется новая компиляция СТ-таблицы. Следующий простой фрагмент иллюстрирует использование указанных средств Maple-языка для создания таблицы интегралов от простых выражений, содержащей только четыре входа (шаблоны подинтегральных выражений) и в качестве соответствующих им выходов – результаты интегрирования исходных шаблонов-выражений.
> T:=([a::algebraic*x::name^(n::integer) = a*x^(n+1)/(n+1), sin(x::name)*cos(x::name)^ (p::integer) = -cos(x)^(p+1)/(p+1), 1/(a::positive+b::positive*x::name^2) = arctan(b*x/ (sqrt(a*b)))/(sqrt(a*b)), sin(n::integer*x::name)^m::integer = int(sin(n*x)^m, x)]); ( ::a algebraic ) ( ::x name)( ::n integer) = a xn + (n + 11), T := (p + 1) sin(x name:: ) cos(x name:: )( ::p integer) = − cos( )x , p + 1 2 = arctan ba bx ,1 ( ::a positive) + ( ::b positive) ( ::x name) a b ( sin ( ::( n integer) ( ::x name)) = m integer:: ) ⌠⌡sin(n x)m dx > compiletable(T): map(tablelook, [10*y^3, sin(z)*cos(z)^3, 1/(1 + 2*h^2), sin(10*x)^3], %); 52y4, −14 cos( )z 4, 12 arctan( 2 h) 2, −301 sin 10( x)2 cos 10( x) − 151 cos 10( x) > map(whattype, [T, %%]); ⇒ [list, function] |
Из представленного фрагмента достаточно прозрачен сам принцип создания функциональной СТ-таблицы и последующего ее использования. Рассмотренные средства пакета Maple обеспечивают простую возможность создания различного рода функциональных таблиц с параметрами и достаточно быстрого их просмотра. При этом, следует иметь в виду, что созданная таким образом функциональная таблица не является в строгом понимании Maple-языка структурой данных table-типа, как это иллюстрирует последний пример предыдущего фрагмента. Более детально читатель может ознакомиться с принципами организации функциональных таблиц в книгах [80,84,86-88].
При этом, следует отметить, что в определенной мере типировать идентификаторы можно и по assume-процедуре, как это иллюстрирует следующий простой пример:
> assume(A, integer); assume(B > 0); frac(A), sin(A*Pi), sqrt(-B); ⇒ 0 0, , B~ IАппарат шаблонов Maple-языка представляет собой довольно развитое уникальное средство, позволяющее проводить структурно-типированный анализ Maple-выражений, однако он не позволяет наделять конструкции языка требуемыми свойствами, подобно тому, как это делает подобный ему механизм математического пакета Mathematica. В деталях данный вопрос здесь не обсуждается и заинтересованный читатель отсылается к книгам [10-14,29,30,84].
Вместе с тем, (::)-оператор типирования поддерживает механизм автоматической проверки типов, передаваемых процедуре значений фактических аргументов, что при конкретном программировании используется весьма широко. В данном случае определяемые в процедуре формальные аргументы по (::)-оператору наделяются соответствующими типами (типируются), позволяя при вызове процедуры на фактических аргументах проверять их допустимость на заданные типы. В дальнейшем указанные средства тестирования типов будут широко использоваться в многочисленных иллюстративных примерах, детализируя их смысловую нагрузку. По конструкции ?{type|typematch|whattype} можно оперативно получать справочную информацию по {type, typematch, whattype} и список всех поддерживаемых Maple-языком типов. Ряд важных особенностей выполнения рассмотренных тестирующих функций можно найти в [12,91], тогда как с введенными нами новыми важными типами можно ознакомиться в [42,103,108,109].
В частности, нами был определен новый file-тип, поддерживаемый процедурой:
type/file := proc(F::anything) local a b c k f SveGal, , , , , ; global _datafilestate; if not type( ,F {'string', 'symbol'}) then return false else c := interface(warnlevel); null interface(( warnlevel = 0)) end if; SveGal := proc( )f try open ,(f 'READ'); close( )f catch "file or directory does not exist": RETURN(false, unassign '( _datafilestate')) catch "file or directory, %1, does not exist": RETURN(false, unassign '( _datafilestate')) catch "file I/O error" RETURN(: false, unassign '( _datafilestate')) catch "permission denied" RETURN(: false, unassign '( _datafilestate')) end try ; true, assign67('_datafilestate' = 'close', f) end proc ; if Empty Red_n( ,( F " " 1, )) then null interface(( warnlevel = c)); ERROR "argument <%1> is invalid",( F) else assign67(a = iostatus( ), b = NULL, f = CF(F)), null(interface(warnlevel = c)) end if; if nops(a) = 3 then SveGal f( ), null interface(( warnlevel = c)) else for k in a[4 .. -1] do if CF(k[2]) = CF( )f then b := b, [k[1], k[2]] end if end do; if b = NULL then SveGal f( ), null interface(( warnlevel = c)) else true, assign67('_datafilestate' = 'open b', ), null interface(( warnlevel = c)) end if end if end proc |
Вызов type(K, file) возвращает true, если K – реальный файл, иначе false возвращается.
Для описания произвольного вычислительного алгоритма рассмотренных выше конструкций Maple-языка явно недостаточно по причине отсутствия средств по управлению вычислительным процессом. Глава и служит целям рассмотрения данных средств Maple.
Современное структурное программирование сосредоточивает свое внимание на одном из наиболее подверженных ошибкам факторов - логике программы - и включает три основные компоненты: нисходящее проектирование, модульное программирование и структурное кодирование. Первые две компоненты достаточно детально нами рассмотрены в книгах [1-3], кратко остановимся на третьей компоненте.