Enumerated sets and sequences can be arbitrarily nested (that is, one may create sets of sets, as well as sequences of sets etc.); tuples can also be nested and may be freely mixed with sets and sequences (as long as the proper Cartesian product parent can be created). Lists can be nested, and one may create lists of sets or sequences or tuples.
Since sequences (and lists) can be nested, assignment functions and mutation operators allow you to use multi-indexing, that is, one can use a multi-index i1, i2, ..., ir rather than a single i to reach r levels deep. Thus, for example, if S=[ [1, 2], [2, 3] ], instead of
> S[2][2] := 4;one may use the multi-index 2, 2 to obtain the same effect of changing the 3 into a 4:
> S[2,2] := 4;All ij in the multi-index i1, i2, ..., ir have to be greater than 0, and an error will also be flagged if any ij indexes beyond the length at level j, that is, if ij>#S[i1, ..., ij - 1], (which means i1>#S for j=1). There is one exception: the last index ir is allowed to index beyond the current length of the sequence at level r if the multi-index is used on the left-hand side of an assignment, in which case any intermediate terms will be undefined. This generalizes the possibility to assign beyond the length of a `flat' sequence. In the above example the following assignments are allowed:
> S[2,5] := 7;(and the result will be S=[ [1, 2], [2, 3, undef, undef, 7] ])
> S[4] := [7];(and the result will be S=[ [1, 2], [2, 3], undef, [7] ]). But the following results in an error:
> S[4,1] := 7;Finally we point out that multi-indexing should not be confused with the use of sequences as indexes to create subsequences. For example, to create a subsequence of S = [5, 13, 17, 29] consisting of the second and third terms, one may use
> S := [ 5, 13, 17, 29 ]; > T := S[ [2, 3] ];To obtain the second term of this subsequence one could have done:
> x := S[ [2, 3] ][2];(so x now has the value S[3]=17), but it would have been more efficient to index the indexing sequence, since it is rather expensive to build the subsequence [ S[2], S[3] ] first, so:
> x := S[ [2, 3][2] ];has the same effect but is better (of course x := S[3] would be even better in this simple example.) To add to the confusion, it is possible to mix the above constructions for indexing, since one can use lists of sequences and indices for indexing; continuing our example, there is now a third way to do the same as above, using an indexing list that first takes out the subsequence consisting of the second and third terms and then extracts the second term of that:
> x := S[ [2, 3], 2 ];Similarly, the construction
> X := S[ [2, 3], [2] ];pulls out the subsequence consisting of the second term of the subsequence of terms two and three of S, in other words, this assigns the sequence consisting of the element 17, not just the element itself!