Darn, after looking at the different use cases the use of negative indexes is not a solution for some cases. The two problematic cases are when the last index value is used in ranges or refer to beyond the current range. Below are examples. I use the double colon
:: as the range operator, where
1::3 results in
{1, 2, 3}. The use of
:: on its own implies all rows or columns.
// Extract 2nd column of matrix excluding first two rows
A = B(3::$, 2)
// Add a row at the bottom of matrix
M($+1, ::) = {13, 14, 15, 16}
The adding of a row or a column to a matrix is a very typical use case. The above two examples cannot be solved with negative indexes. Lets look at each case individually.
Ranges
The range 1::-1 is an invalid range. A possible solution is to use notation like k:: to indicate from k to the end in increments of 1, and k::i:: to indicate from k to the end in increments of i. To make it symmetrical one can also use ::n to indicate from the start to n, but the start will always be 1, so its not really necessary. In my current implementation the :: operator returns a range object and not the expanded list. In this case it can return a range object with a special value for the end value which indicates "to the end". The above example will then read as follows
// Extract 2nd column of matrix excluding first two rows
A = B(3::, 2)
Adding rows/columns
One cannot refer to 1 beyond the end (or k beyond the end in general) using negative indexes. A possible solution is to introduce a special prefix operator like #+ that means "the end plus ...". The # reminds of the table size operator of Lua. This operator will return a special index object which can be interpreted at run-time by the matrix object. The will look as follows:
// Add a row at the bottom of matrix
M(#+1, ::) = {13, 14, 15, 16}
Referring to the end row/column or before
For this case the negative indexes will work well, for example:
// Replace the second-last row
M(-2, ::) = {13, 14, 15, 16}
Any comments or suggestions?