Так как выражение представляет собой более широкое понятие, чем данные (значения), то для тестирования их типов Maple-язык располагает достаточно развитым набором средств. Прежде всего, для прямого определения типа выражения используется уже упомянутая процедура whattype, имеющая простой формат кодирования: whattype(<Выражение>) и возвращающая тип заданного выражения, если он является одним из нижеследующих:
`*` `+` `.` `..` `::` `<` `<=` `<>` `=` `^` `||` `and` array complex complex(extended_numeric) exprseq extended_numeric float fraction function hfarray implies indexed integer list module moduledefinition `not` `or` procedure series set string symbol table uneval unknown `xor` zppoly Array Matrix SDMPolynom Vector[column] Vector[row]
Приведенный перечень идентифицируемых типов выражений, включая некоторые данные и их структуры, представлен для Maple 10, тогда как для более низких релизов этот перечень несколько короче. Следует еще раз подчеркнуть, что хотя тип последовательности (exprseq) не является определяемым функциями type, typematch типом, однако он идентифицируется whattype-процедурой. При этом, процедура возвращает только тип высшего уровня вложенности выражения в соответствии с приоритетным порядком составляющих его операторов. Следующий пример иллюстрирует применение тестирующей whattype-процедуры:
> [whattype(64), whattype(x*y), whattype(x+y), whattype(x<=y), whattype(a<>b), whattype([]), whattype(a = b), whattype(a^b), whattype(Z), whattype(h(x)), whattype(a[17]), whattype({}), whattype([]), whattype(x,y), whattype(table()), whattype(x..y), whattype(5.9), whattype(A and B), whattype(proc() end proc), whattype(module() end module), whattype(10/17), whattype("SV"), whattype(a.b), whattype(hfarray(1..10))];
[integer, *, +, <=, <>, list, =, ^, symbol, function, indexed, set, list, exprseq, table, .. , float, and, procedure, module, fraction, string, function, hfarray]
При этом, имеют место следующие идентификации типов whattype-процедурой:
{+|-} → + {/|*} → * {>=|<=} → <= {>|<} → < {**|^|sqrt(a)} → ^
{a|a."b"|a.b|a.`b`|`a`.b|`a`.`b`} → symbol {"a"|"a"."b"|"a".`b`|"a".b} → string
{array|vector|matrix} → array
что следует учитывать при использовании указанной процедуры тестирования. Обусловлено это тем обстоятельством, что предварительно вызов процедуры whattype(A) вычисляет и/или упрощает выражение А. Для расширенного тестирования типов выражений служит вышерассмотренная в связи с данными и их структурами функция {type|typematch}. Приведем простой пример на применение type-функции для тестирования выражений:
> [type(sqrt(x)+a/b, 'anything'), type(a**b, `**`), type(x*y+z^a, dependent(z)), type('a.b', `.`), type(x^a-3*x+x^4-47 = b, 'equation'), type(x^3+4*x-56, 'expanded'), type(ifactor(1998), 'facint'), type(h!, `!`), type(F(x), 'function'), type(G[47, 51, 42, 67, 62], 'indexed'), type(5*y^4
+ x^3 - 47*x, 'quartic(y)'), type(arctanh, 'mathfunc'), type(`Salcombe Eesti`, 'symbol'), type(ln, 'mathfunc'), type(10/17, 'numeric'), type(A -> B, 'operator'), type({G = 51, V = 56}, 'point')];
[true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]
Следует упомянуть еще об одной тестирующей функции hastype(expr,t), чей вызов возвращает true-значение, если выражение expr содержит подвыражение заданного t-типа, и false-значение в противном случае, например:
> map2(hastype, (a*x + 10)/(sin(x)*y + x^4), ['integer', 'symbol', 'function', `*`, `+`, symbol^integer]);
[true, true, true, true, true, true]
> map2(hastype, (10^Kr + 96)/(Art^17 + 89), [even^symbol, symbol^odd]); ⇒ [true, true]
При этом, можно проводить тестирование выражений как относительно простых типов, так и структурных, как это иллюстрирует второй пример предыдущего фрагмента.
Дополнительно к рассмотренным средствам тестирования рассмотрим еще 6 весьма полезных процедур из класса так называемых is-процедур языка. Прежде всего, процедура isprime(n) осуществляет стохастическую проверку n-числа на предмет его простоты, тогда как процедура issqr(n) тестирует наличие точного квадратного корня из целого n-числа. Процедура is(V, <Свойство>) тестирует наличие у V-выражения указанного свойства, тогда как процедура ispoly(P, {1|2|3|4}, x) тестирует будет ли P-выражение полиномом {1|2|3|4}-степени по ведущей х-переменной. Процедура isdifferentiable(V,x,n) тестирует V-выражение, содержащее кусочно-определенные функции (abs, signum, max и др.), на предмет принадлежности его к Cn-классу по ведущей х-переменной. Наконец, процедура iscont(W, x=a .. b{, 'closed'}) тестирует факт наличия непрерывности W-выражения на [a, b]-интервале по x-переменной, включая его граничные точки, если закодирован необязательный closed-аргумент. Простой фрагмент иллюстрирует использование указанных is-процедур:
> iscont(x*sin(x) + x^2*cos(x), x= -Pi..Pi, 'closed'); ⇒ true
> isprime(1999), isprime(1984979039301700317); ⇒ true, false
> issqr(303305489096114176); ⇒ true
> x:= 32: is(3*sin(x) + sqrt(10) + 0.42, 'positive'); ⇒ true
> ispoly(3*h^4 - 10*h^3 + 32*h^2 - 35*h + 99, 'quartic', h); ⇒ true
> isdifferentiable(y*(abs(y)*y + signum(y)*sin(y)), y, 2); ⇒ false
Под структурированным типом в Maple-языке понимается выражение, отличное от имени (не идентифицируемое отдельным словом), но которое может быть интерпретировано как тип. В общем случае структурированный тип представляет собой алгебраическое выражение от известных языку типов, которое в основных чертах наследует структуру тестируемого выражения. На основе механизма структурированных типов предоставляется возможность тестировать как структуру выражения в терминах его подвыражений, так и их типовую принадлежность в терминах базовых типов языка. Особый смысл данная возможность приобретает в задачах символьных обработки и вычислений. Следующий фрагмент иллюстрирует вышесказанное:
> type([64, V, sqrt(Art)], [integer, name, `^`]), type(59^sin(x), integer^trig); ⇒ true, true
> type(G(x)^cos(y), function^symmfunc), type(sqrt(F(x)), sqrt(function)); ⇒ true, true
> type(57+sin(x)*cos(y), `&+`(integer, `&*`(trig, symmfunc))); ⇒ true
> type(sqrt(Art^10 + Kr^3 + 99),sqrt(`&+`(name^even, symbol^odd, integer))); ⇒ true
> type((G(x) + cos(y))^(47*I + sin(x)),(`&+`(function, trig)^`&+`(complex, trig(x)))); ⇒ true Из примеров представленного фрагмента вполне прозрачно прослеживается тесная взаимосвязь между структурным деревом термов тестируемого выражения и выбранным для него структурированным типом. Детальнее с вопросами структурированных типов языка можно ознакомиться по книгам [33,42,45,83] либо оперативно по конструкции вида ?type, {anyfunc| identical|specfunc|structure} в среде текущего сеанса пакета.
Следует иметь в виду, что по конструкции следующего простого вида: type('<Id>', name(<Тип>))
предоставляется возможность тестировать тип присвоенного Id-идентификатору значения, как это иллюстрирует следующий весьма простой фрагмент:
> GS:= cos(x)*sin(y) + F(z) + 99: AV:= 42 .. 64: type('AV', name(range)); ⇒ true
> SV:= sqrt(Art + Kr): type('SV', name(sqrt(`&+`(name, symbol)))); ⇒ true
> type('GS', name(`&+`(`&*`(symmfunc, trig), function, odd))); ⇒ true
Как следует из приведенного фрагмента, описанный механизм позволяет производить тестирование типов значений определенных переменных в терминах как базовых типов языка, так и структурированных типов, существенно расширяя возможности языка. Для автоматического тестирования типов выражений, прежде всего, в процедурных конструкциях, используется (::)-оператор типирования, детально рассматриваемый несколько ниже в связи с процедурными объектами.
Особого внимания заслуживают еще две тестирующие функции, позволяющие проводить структурное тестирование типов как выражений, так и составляющих их подвыражений. В частности, hastype-функция имеет следующий формат кодирования: hastype(<Выражение>, <Структурированный тип>)
и возвращает логическое true-значение только тогда, когда Выражение содержит подвыражения указанного структурированного типа, например:
> Kr:= 10*sin(x) + 17*cos(y)/AV + sqrt(AG^2 + AS^2)*TRG + H^3 - 59*sin(z) - Catalan:
> map2(hastype,Kr, [name^integer,constant,sqrt,fraction,`*`]); ⇒ [true, true, true, true, true]
> map2(has,Kr,[10*sin(x), 1/AV, AG^2+AS^2, H^3,-59*sin(z)]); ⇒ [true, true, true, true, true] > [hasfun(Kr, sin, z), map2(hasfun, Kr, [sqrt, sin, cos])]; ⇒ [true, [false, true, true]]
Из приведенного фрагмента нетрудно заметить, что в качестве второго аргумента функции hastype могут выступать не просто рассмотренные выше допустимые языком пакета типы, но и их структурированные конструкции, отвечающие структурам входящих в тестируемое выражение подвыражений. На основе данной функции можно не только тестировать выражения на типы составляющих их подвыражений, но также на их структурную типизацию в рамках общей структуры исходного выражения.
По тестирующей функции has(<Выражение>, <Подвыражение>) производится проверка на наличие вхождения в заданное первым аргументом выражение указанного вторым аргументом подвыражения. Если в качестве второго аргумента has-функции указан список подвыражений, то выражение подвергается тестированию по каждому из подвыражений списка. Функция возвращает true-значение, если факт вхождения установлен, и falseзначение в противном случае. При этом, в случае списка подвыражений в качестве второго аргумента has-функция возвращает true-значение только тогда, когда имеет место факт вхождения в тестируемое выражение по крайней мере одного из подвыражений указанного списка. Второй пример предыдущего фрагмента иллюстрирует сказанное. Данная функция представляет большой интерес в задачах структурного анализа символьных выражений, поступающих в качестве входной информации для процедур символьных обработки и вычислений.
Наконец, по тестирующей функции hasfun(V,<Id-функции> {,x}) возвращается значение true, если определенное первым фактическим аргументом V-выражение содержит вхождение функции, заданной своим идентификатором, и, возможно, от указанной третьим необязательным аргументом ведущей х-переменной. Последний пример предыдущего фрагмента не только иллюстрирует вышесказанное, но и указывает на то, что, в частности, sqrt-функция не тестируется hasfun-функцией. Ряд дополнительных вопросов, относящихся к тестированию выражений, рассматривается несколько ниже.