> L:= [a, c, [h], x, [a, b, []]]: type([], nestlist), type([[]], nestlist), type(L, nestlist), type([[[]]], nestlist), type([[61], [56], [36], [7], [14]], nestlist), type([a, b, c, {}], nestlist); false, true, true, true, true, false
В ряде задач, имеющих дело со структурами set-типа, возникает потребность использования так называемых setset-структур (аналогично listlist). Скажем, множество имеет тип 'setset', если его элементы – множества того же самого количества элементов. Для проверки множества на setset-тип служит расширение стандартной type-функции [41,103], т.е. вызов процедуры type(S, 'setset') возвращает true, если множество, определенное первым фактическим S аргументом, имеет setset-тип, и false в противном случае, например:
> map(type, [{{}}, {{},{}}, {{{7}}}, {{a, b}, {c, d}}, {{a, b}, {c}}, {{10, 17}, {64, 59}, {39, 44}}], 'setset');
[true, true, true, true, false, true]
По функции sort(L {, СФ}) производится сортировка элементов L-списка либо согласно принятому в пакете соглашению (определяемому типом элементов списка), либо согласно заданной сортирующей функции (СФ), устанавливающей приоритет между любыми двумя элементами списка. А именно, СФ G(x, y) возвращает {true|false}-значение в зависимости от {соответствия|несоответствия} двух смежных {x, y}-элементов L-списка и в зависимости от него {не меняет|меняет} их местами в выходном L`-списке. Наиболее типичными примерами СФ, поддерживаемыми Maple-языком, являются: address, numeric, `<` и lexorder; при этом, первая и последняя определяют сортировку соответственно адресную (в соответствии со значениями адресов, занимаемыми в памяти элементами списка) и лексикографическую. Если СФ-аргумент sort-функции не указан, то числовой список сортируется согласно значениям чисел в порядке их возрастания, символьный (строчный) список – в лексикографическом порядке, в остальных случаях производится адресная сортировка, которая зависит от текущего сеанса работы с пакетом (в свете планирования для пакета памяти ПК). Пользователь имеет возможность определять собственные СФ, решающие специфические задачи сортировки; один из примеров такой СФ (SF) приведен в нижеследующем простом фрагменте:
> SF:=(X::{string,symbol}, Y::{string,symbol}) -> `if`(""||X = "" and ""||Y = "" or ""||X="", true, `if`(""||Y = "", false, `if`(sort([(""||X)[-1], (""||Y)[-1]], 'lexorder')[1] = (""||X)[-1], true,false))): sort(["12345", xyz, `123d`, "123a", `123c`, ``, abc, "", ta,avz64, agn59, vsv39],SF);
[``, "", avz64, "12345", agn59, vsv39, "123a", ta, 123c, abc, 123d, xyz]
Для работы со списками и множествами нами был предложен целый ряд достаточно полезных процедур [103], в частности, полезной во многих приложениях является процедура SLj, обеспечивающая сортировку вложенных списков на основе заданных позиций элементов их подсписков. Ниже представлены ее исходный текст и пример применения.
SLj := proc(L::nestlist, n::posint) local a b c k p R, , , , , ; assign(b = map(nops, {op(L)})[1], c = nops(L)), `if`(b < n, ERROR("invalid 2nd argument <%1>; must be >= 1 and <= %2", n b, ), assign(R = [ ] )) , assign(a = sort [( op {( seq(L k[ ][n], k = 1 .. c)})], `if`(2 < nargs and type(args[3], 'boolproc'), args[3], NULL))); for k to nops(a) do for p to c do if a k[ ] = L p[ ][n] then R := [op(R), L p[ ]] end if end do end do; R end proc > K:= [[a,b,c], [g,d,c], [a,g,c,c,c,l], [l,s,a], [f,d,k,k], [s,a,d,b,w,q,s,d,a]]: SLj(K, 2, 'lexorder'); [[s, a, d, b, w, q, s, d, a], [a, b, c], [g, d, c], [f, d, k, k], [a, g, c, c, c, l], [l, s, a]] |
В качестве обобщения процедуры SLj можно рассматривать процедуру snl, чей исходный текст и примеры применения приводяюся в нижеследующем фрагменте. При этом, в первом примере приводится расширение типа ‘relation’, полезное в целом ряде приложений, имеющих дело с выражениями relation-типа.
type/relation1 := proc(x::symbol) if member(x, {`=` `>` `>=` `<` `<=` `<>`, , , , , }) then true else false end if end proc > map(type, [`<`, `<=`, `=`, `<>`, `>=`, `>`], 'relation'); [false, false, false, false, false, false] > map(type, [`<`, `<=`, `=`, `<>`, `>=`, `>`], 'relation1'); [true, true, true, true, true, true] snl := proc(L::nestlist, f::procedure, p::list(posint )) local a b sf k, , , ; seq `if`( ( not type(map(evalf k, ), list(numeric)), ERROR("element %1 has a type different from list or is non-numeric list", k) , `if`(sort(p)[-1] ≤ nops( )k , NULL, ERROR("sublist %1 has length more than maximal element of list %2", k, p))) , k = L); if nargs = 3 then a := `<=` elif 4 ≤ nargs and type(args 4[ ], 'relation1') then a := args 4[ ] else WARNING("4th argument has a type different from relation1; for it defau\ lt value had been set"); a := `<=` end if ; sf := proc (L1 L2, ) local k, j; evalb(evalf(a(f(seq(L1 k[ ], k = p)), f(seq(L2 j[ ], j = p))))) end proc ; sort(L sf, ) end proc |
> f:= () -> `+`(args): snl([[2,6,9], [11,34,47], [67,2,10,18]], f, [1, 2, 3], `>`);
[[11, 34, 47], [67, 2, 10, 18], [2, 6, 9]]
> snl([[2,6,9], [11, 34, sin(18)], [67, 2, 10, 18]], f, [1, 2, 3]);
[[2, 6, 9], [11, 34, sin(18)], [67, 2, 10, 18]]
> snl([[2,6,9], [11,34,47], [67,2,10,18]], f, [1, 2, 5], `>`);
Error, (in snl) sublist [2, 6, 9] have length more than maximal element of list [1, 2, 5] > snl([[2,6,9], 2007, [67,2,10,18]], f, [1, 2, 3]);
Error, (in snl) element 2007 has a type different from list or is non-numeric list
Первый аргумент вызова процедуры snl(L, f, p) определяет вложенный список, тогда как второй определяет процедуру, чьи фактические аргументы получают в качестве значений элементы подсписков L, стоящие на указанных аргументом р позициях. Подсписки L по умолчанию сортируются в зависимости от значений f(x1, x2, …) согласно функции упорядочивания `<=`; четвертый необязательный аргумент определяет упорядочивающую функцию из множества {`<`, `<=`, `>`, `>=`}. Сортировке подвергаются только числовые вложенные списки, в противном случае инициируется ошибочная ситуация.
Нижеследующий фрагмент первым примером представляет процедуру, обеспечивающую один вид полезной конвертации произвольного Maple-выражения L на основе составляющих его операндов. В частности, данный тип конвертации достаточно полезен в случае необходимости конвертации списка/множества в выражение, представляющее собой «склейку» входящих в исходной объект элементов. Тогда как второй пример фрагмента представляет один полезный вид сортировки списочных структур на основе процедуры slsa, использующей представленные выше процедуры.
`convert/opexpr` := proc(L::anything) if type(evalf(L), 'numeric') then L else parse(cat(op(map(convert, [op(L)], 'string')))) end if end proc > convert([A, V, 1942, "AVZ+AGN", RANS_IAN, 42, 47, 67, 10, 18], 'opexpr'); AV1942AVZ + AGNRANS_IAN4247671018 slsa := proc (L::list({algebraic, string, symbol})) local a b c k ss, , , , ; assign(a = [ ], b = [ ]), seq `if` type(( ( evalf( )k , 'numeric'), assign(' 'a = [op(a), k]), assign(' 'b = [op(b), k])), k = L); ss := (a anything:: , b anything:: ) → `if`(c(convert(convert( convert(evalf(a), 'string'), `if`(type(evalf(a), 'numeric'), 'string', 'bytes')) , opexpr ), convert convert convert( ( (evalf(b), 'string'), `if`(type(evalf(b), 'numeric'), 'string', 'bytes')), opexpr )), true false, ); assign(c = `<=`), `if`(1 < nargs and type(args 2[ ], 'relation1 '), assign(' 'c = args 2[ ]), NULL) , [op(sort(a, ss)), op(sort(b, ss))] end proc > slsa(["a", 678,"arf",1942,"yrt",sqrt(2),"aqw", 2007,64,59, (avz+agn)/(Art+Kr), sin(18), 10]); sin 18( ), 2 10 59 64 678 1942 2007, , , , , , , "a" "aqw" "arf" "yrt", , , , avzArt + + agnKr > slsa(["a",678,"arf",1942,"yrt",sqrt(2),"aqw",2007,64,59,(avz+agn)/(Art+Kr),sin(18),10], `>=`); 2007 1942 678 64 59 10, , , , , , 2, sin(18), avzArt + + agnKr , "yrt" "arf" "aqw" "a", , , > slsa(["a","arf","yrt","aqw", (avz+agn)/(Art+Kr), RANS_RAC_REA_IAN], `>=`); avzArt + + agnKr , RANS_RAC_REA_IAN, "yrt" "arf" "aqw" "a", , , |
> slsa(["a","arf","yrt","aqw", (avz+agn)/(Art+Kr), RANS_RAC_REA_IAN]); "a" "aqw" "arf" "yrt", , , , RANS_RAC_REA_IAN, avzArt + + agnKr |
Вызов процедуры slsa(L) возвращает результат сортировки списка L с элементами типов {algebraic, string, symbol} в порядке возрастания элементов. При наличии второго необязательного аргумента relation1-типа сортировка определяется заданным отношением. При этом, в начале отсортированного списка находятся (если имеются) элементы с числовыми эначениями а (для которых type(evalf(a), ‘numeric’) ⇒ true), за которыми следуют (при наличии) элементы других допустимых типов.
В свете сказанного, во многих случаях можно рассматривать множества как упорядоченные объекты и использовать данное обстоятельство в различных приложениях. В общем же случае это не имеет места, поэтому использовать его следует весьма осмотрительно. Именно по этой причине для удаления элемента из множества недопустимо использование конструкций, рассмотренных выше для случая списочных структур. Этих целей нами был предложен ряд средств [41,103,108,109]. В частности, нижеследующая процедура
insituls := proc(L::uneval, a::{equation, list(equation ), set(equation )}) if not type( ,L 'symbol') then error "1st argument must be symbol but had received %1"whattype(, L) elif type(eval(L), {'set', 'list'}) then assign( ' 'L = subs([`if`( not type( ,a {'set', 'list'}), a, seq(k, k = a))], eval(L))) else error "1st argument must has type {list, set} but had received %1-type", whattype eval(( L)) end if end proc > L:= [64,59,39,44,10,17]: insituls(L, [64=42, 59=47, 17=89]), L, insituls(L, 44=NULL), L; [42, 47, 39, 44, 10, 89], [42, 47, 39, 10, 89] > S:= {64,59,39,44,10,17}: insituls(S, [64=42, 59=47, 17=89]), S, insituls(S, 44=NULL), S; {10, 39, 42, 44, 47, 89}, {10, 39, 42, 47, 89} |
Вызов процедуры insituls(L, a) обеспечивает обновление элементов списка/множества L «на месте»; при этом, a-аргумент может быть уравнением либо списком/множеством уравнений, определяющих замены в L. Левые части уравнений определяют текущие элементы списка/множества L, тогда как его правые – замены для текущих элементов. В частности, NULL в качестве правой части удаляет соответствующий элемент из L. Успешный вызов процедуры возвращает NULL-значение, выполняя требуемое обновление списка/множества L «на месте».