> 64 in [59, 39, 64, 10, 17, 44]; evalb(%); ⇒ 64 ∈ [59, 39, 64, 10, 17, 44] true
> evalb(`in`(64, [59, 39, 64, 10, 17, 44])); ⇒ true
Детальнее с данным оператором in можно ознакомиться в справке по пакету.
К member-функции по смыслу, но с более широкими возможностями, примыкает и процедура charfcn[A](X), являющаяся характеристической для множеств и алгебраических Maple-выражений. В качестве Х выступает произвольное алгебраическое выражение, а в качестве А - спецификатор множества. Кусочно-определенная charfcn-процедура задается следующим определяющим соотношением:
1, если Х удовлетворяет А-спецификатору
charfcn[A](X) =0, если Х не удовлетворяет А-спецификатору
'charfcn[A](X)', в противном случае
В качестве А-спецификатора может выступать множество, действительное или комплексное значение, диапазон действительных или комплексных значений либо последовательность выражений любого из перечисленных выше типов. Тогда как смысл выражения "удовлетворяет А-спецификатору" определяется следующей табл. 10.
Таблица 10
Спецификатор А | Смысл: Х удовлетворяет А-спецификатору |
Множество | member(X, A) ⇒ true |
А - действительное или комплексное | X = A |
a .. b; a, b - действительные числа | a <= X <= b; допускаются ±infinity-значения |
a .. b; a, b - комплексные значения | Re(a) <= Re(X) <= Re(b) и Im(a) <= Im(X) <= Im(b) |
A1, A2, … ,An; Ak - выражение одного из предыдущих типов | удовлетворяет одному из Ak-спецификаторов |
Примеры нижеследующего фрагмента иллюстрируют применение charfcn-процедуры, в частности, удобной в числовых вычислениях, как иллюстрирует последний пример.
> charfcn[64, 59, 39, 10, 17](17), charfcn[64, 59, 39, 10, 17](44); ⇒ 1, 0
> charfcn[1 .. 64](59), charfcn[3.1 .. 3.3](Pi), charfcn[2+I .. 17+2*I](2+I); ⇒ 1, 1, 1 > G:= X -> 64*charfcn[1..9](X)+59*charfcn[10..17](X)+39*charfcn[18..25](X)+17* charfcn[-infinity .. 0, 26..infinity](X): map(G, [2, 12, 20, -3, 32]); ⇒ [64, 59, 39, 17, 17]
Последний пример фрагмента иллюстрирует использование характеристической функции charfcn для определения кусочно-определенной G-функции.
Следующие две функции select и remove, имеющие идентичный формат кодирования:
{select|remove}(ТФ, <Выражение> {, <Фактические аргументы>})
позволяют {выбирать|удалять} из указанного выражения только те его операнды (элементы), которые на заданной тестирующей функции (ТФ) возвращают true-значение. При этом, необязательный третий аргумент {select|remove}-функции позволяет передавать для ТФ необходимые фактические аргументы, например, фактические значения для второго аргумента функции {type|typematch}. Функция {select|remove} применима к спискам, множествам, суммам, произведениям и функциям, возвращая конструкции, тип которых определяется типом исходного выражения, например:
> select(type, [64,59,39,10,17],'even'), remove(type, [64,59,39,10,17],'odd'); ⇒ [64,10], [64,10]
По subsop-функции, имеющей следующий простой формат кодирования: subsop(p1 = B1, p2 = B2, ... ,pn = Bn, <Список/Множество>)
производится замена всех элементов указанного списка/множества, находящихся на его pj-позициях, на указанные Bj-выражения; в случае вложенного списка/множества в качестве pj-позиций указываются списки (подобно рассмотренному для случая op-функции). Если subsop-функция не содержит уравнений замены (pj = Bj), то указанный список/множество возвращается без изменения. В общем случае, функция subsop применима к любому Maple-выражению, содержащему операнды. При этом, нулевые значения для pjпозиций допустимы только для выражений типа функция, индексированное выражение или ряд. Замечания, сделанные относительно op-функции, сохраняют силу и для функции subsop, например:
> subsop(1=42, 2=47, 3=76, 4=96, 5 = 89, [64, 59, 39, 10, 17]); ⇒ [42, 47, 76, 96, 89]
Близка к subsop-функции по идеологии и applyop-процедура с форматом кодирования: applyop(F, p, <Выражение> {, <Фактические аргументы>})
и применяющая указанную своим идентификатором F-функцию к операнду, находящемуся на заданной р-позиции выражения; при необходимости можно определять фактические аргументы для передачи их F-функции. Аргумент позиция (р) applyop-процедуры определяется номером позиции операнда (элемента), списком позиций (аналогично случая subsop-функции) либо множеством позиций операндов, к которым F-функция применяется одновременно. Особенности выполнения процедуры см. в прилож. 1 [12]. Приведем простой пример применения процедуры applyop:
> applyop(F, {1, 2, 3}, [x, y, z], a, b, c, d); ⇒ [F(x, a, b, c, d), F(y, a, b, c, d), F(z, a, b, c, d)]
В отличие от applyop-процедуры ранее упоминавшаяся map-функция с форматом: map(F, <Выражение> {, <Фактические аргументы>})
позволяет применять F-функцию/процедуру, заданную своим идентификатором, к каждому операнду указанного выражения с возможностью передачи F-функции необходимых фактических аргументов, которые в общем случае кодирования map-функции необязательны. По map-функции указанная F-функция применяется ко всем элементам структур типа {list, set, array, table}. Дальнейшим расширением данной функции является map2-функция, также рассмотренная нами выше. Следующий прозрачный фрагмент иллюстрирует применение обоих функций с акцентом на их различиях:
> map(G, [x, y, z, u], a, b, c); ⇒ [G(x,a,b,c), G(y,a,b,c), G(z,a,b,c), G(u,a,b,c)]
> map2(G, [x, y, z, u], a, b, c); ⇒ G([x, y, z, u],a,b,c)
> map(G, t, [x, y, z, u], a, b, c); ⇒ G(t, [x, y, z, u], a, b, c)
> map(map2, [x, y, z], a, d, c); ⇒ [x(a,d,c), y(a,d,c), z(a,d,c)]
> map2(map, [x, y, z], a, d, c); ⇒ [x(a,d,c), y(a,d,c), z(a,d,c)]
> map(map2, h, [x, y, z], a, d, c); ⇒ h([x, y, z],a,d,c)
> map2(map, h, [x, y, z], a, d, c); ⇒ [h(x,a,d,c), h(y,a,d,c), h(z,a,d,c)]
В порядке расширения возможностей функций map и map2 нами создан ряд подобных процедур map3 .. map6 и mapN [41,103]. В частности, вызов процедуры mapN(F, p, x1, x2, …, xn, [a, b, c, …]) возвращает результат вычисления функции F от аргументов <x1, x2, …, xn> при условии получения его p-м аргументом значений из списка или множества, определенного последним фактическим аргументом процедуры. Процедура представляется достаточно полезным дополнением к вышеупомянутым двум стандартным функциям пакета. Ниже представлены исходный текст процедуры mapN и пример ее применения.
mapN := proc(F::symbol, p::posint) local k; `if`(nargs − 3 < p, ERROR(`position number <%1> is invalid` p, ), `if`(p = 1, convert [( seq(F(args -1[ ][ ]k , args 4 .. -2[ ]), k = 1 .. nops(args -1[ ]))], whattype args[-1] ) `if`( ) , (p = nargs − 2, cnvtSL( [seq(F(args[3 .. -2], args[-1][k]), k = 1 .. nops(args[-1]))], whattype(args[-1])) , cnvtSL( [seq(F(args 3 .. [ p + 1], args -1[ ][ ]k , args[p + 3 .. -2]), k = 1 .. nops(args -1[ ]))], whattype args[-1] ))))( ) end proc > F:= (x, y, z, r, t, h) -> G(x, y, z, r, t, h): mapN(F, 6, x, y, z, r, t, h, [a, b, c, d, e, f, n, m, p, u]); [G(x,y,z,r,t,a), G(x,y,z,r,t,b), G(x,y,z,r,t,c), G(x,y,z,r,t,d), G(x,y,z,r,t,e), G(x,y,z,r,t,f), G(x,y,z,r,t,n), G(x,y,z,r,t,m), G(x,y,z,r,t,p), G(x,y,z,r,t,u)] |
По вызову функции subs(L, <Выражение>) возвращается результат подстановки в указанное вторым аргументом выражение всех вхождений левых частей уравнений, определяемых списком/множеством L, на их правые части. При этом, в качестве L-аргумента может выступать и отдельное уравнений (отдельная подстановка). Подстановка правых частей уравнений производится одновременно, используя естественный порядок уравнений в L-списке/множестве. Более того, подстановке подвергаются только операнды исходного выражения, распознаваемые op-функцией, независимо от уровня их вложенности. Однако, подстановка производится только для строгого вхождения левых частей уравнений, определяя так называемую синтаксическую подстановку. При этом, подстановка не влечет за собой непосредственного вычисления выражения и для этих целей следует использовать затем eval-функцию, которая, однако, в общем случае не обеспечивает полного вычисления результата подстановки, как это иллюстрируют примеры следующего простого фрагмента:
> subs([x=a,y=b,z=c], [x,y,z,a*x, b*y, c*z, x+y+z, x*y*z]); ⇒ [a b c a, , , 2, b2, c2, a + b + c a b c, ]
> subs(x=Pi, sin(x)+cos(x)), eval(subs(x=Pi, sin(x)+cos(x))); ⇒ sin(π) + cos(π), -1
> subs([ooo=a,aao=b,oaa=c,aoa=d], [ooo,aao,oaa,ooo,aoa,aao,aao,oaa]); ⇒ [a, b, c, a, d, b, b, c] > subs([oo=NULL, aa=NULL, ao=NULL, oa=NULL], [oo, aa, aa, oo, ao, aa, ao, oa]); ⇒ [] > subs({oo=NULL, aa=NULL, ao=NULL, oa=NULL}, {oo, aa, aa, oo, ao, aa, ao, oa}); ⇒ {}
Как следует из примеров фрагмента, по subs-функции можно не только заменять элементы списка/множества на основе их значений, но и удалять требуемые элементы.
Под структурой listlist-типа понимается вложенный список, все элементы первого (внешнего) уровня которого являются списками той же длины, что и содержащий их список, например: [[a, b, c], [d, e, f], [g, h, i]]. Такой объект распознается type-функцией как объект listlist-типа, например, type([[a,b,c], [d,e,f], [g,h,i]], 'listlist'); ⇒ true. По convert-функции можно конвертировать {список|массив} в список списков (listlist); при этом, сам список должен задаваться уравнениями вида <позиция списка> = <элемент списка>. Однако в ряде версий 6-го релиза вызов convert(R::array, listlist) вызывает ошибочную ситуацию с диагностикой "Error, in convert/old _ array_to_listlist) Seq expects its 2nd argument .… ". Для устранения данной ситуации может использоваться модификация стандартной функции – процедура 'convert/listlist1' [41,103,109], которая обеспечивает конвертацию списка, множества, массива либо rtable-объекта в listlist-объект, например:
> convert([2=64, 3=10, 4=39, 5=59, 1=17, 6=44], 'listlist1'); ⇒ [17, 64, 10, 39, 59, 44]
В ряде задач, имеющих дело со структурами list-типа, возникает потребность использования так называемых вложенных структур списков (nestlist). Скажем, список – вложенный список, если по крайней мере один его элемент имеет list-тип. Для проверки списка быть вложенным списком служит расширение стандартной type-функции [103]. Вызов процедуры type(expr, 'nestlist') возвращает true, если список, определенный первым фактическим expr аргументом является вложенным списком, и false в противном случае, например: