Expression Pattern Language (eXPL)

Cursor

Cursor is a list variable which has an internal index which is controlled by a small number of operators. The index value may be set, incremented, decremented or changed by adding an integer value. These are the cursor index operators:

OperatorDescription
++Postfix operator increments the index
--Postfix operator decrements the index
+Resets index to 0, the default value
-Resets index to position of last item in list
=Sets index to value on right hand side
+=Adds to index value on right hand side

A cursor can be dereferenced the same as any list variable using the [] operator, but the value in the expression is interpreted as relative to the internal index value. Thus a value of 0 references the item at the current cursor position. This means negative values can be used.

Format

A cursor can only be declared in a template or calculator and only as an attachment. The cursor may optionally be assigned a type if type conversion is desired:

cursor[<type>] name(list-name);

A cursor is ready for use upon creation, with the initial internal index value set to zero. To commence navigation from a different position, the index may be set by any of these operators: [ = - += ]. To return to the initial state, use + operator.

Note that syntax rules may only allow unary operators to be used when placed on the right hand side of an expression. This applies to ++ and -- for calculator and extends to + and - for template.
Pet Names Example

The PetNames application of tutorial9 uses a cursor named "pet_cursor" to iterate through a list of pet details in XML format, extract the name of each pet and export the names as a list. The companion ReversePetNames application creates the same list in reverse. This is the calculator for the first application:

calc pets
+ export list<string> pet_names;
+ cursor pet(pets_info);
(
string petRegex =
"^.*" + nameRegex +".*",
{
? pet.fact,
regex (pet++) == petRegex { name },
pet_names += name
}
);

Note how the fact attribute of the cursor is used to detect the end of the list has been reached. It is good practice to check the cursor fact status before reading the cursor in case the list is empty for some unexpected reason. Note too that the cursor expression "pet++" is in parentheses because regex syntax needs to distinguish between expressions and identifiers this way. An infinite loop would occur if the regex failed to match without the cursor having been advanced first.

You will see that for reverse traversal of the list, an extra preparation step is required to set the cursor to last item in the list:

-pet,

To do the same in a template you need to to avoid unary operator prohibition. This example uses an expression with a dummy variable named "backwards":

backwards = -pet,

Type Conversion

A cursor can be assigned a type so that it performs type conversion when items are fetched from the list. Application CurrencyCursor of tutorial9 demonstrates this by using a currency cursor to convert Euro amounts in text format to decimal numbers. The program translates the Euro amounts in a succinct manner, with an appender and cursor working in tandem. This is the cursor declaration which specifies Germany as the currency country :

+ cursor<currency $ "DE"> euro_amount(euro_amounts);

and this is where the type conversion takes place:

amount_list += euro_amount++,

Here the appender, "amount_list" adds the next converted amount from cursor "euro_amount" which advances to next amount at the same time.

Insertion Sort

A cursor is generally useful for data processing as will be shown by revisiting the insert sort examples of tutorial8 and applying a cursor to do the shuffling. The insert sort requires navigation starting from somewhere inside the list and progressing in the reverse direction. The cursor in both examples is called "sorter". Here is the shuffle code from HighCitiesSorted3 of tutorial9:

sorter = j,
{
? altitude < sorter[0].altitude,
sorter[1] = sorter--,
? --j >= 0
},

The cursor makes the code more abstract and easier to follow. There is still a loop variable "j" which is needed after the loop to do the outstanding insert operation. Note the cursor is set to the right start position simply by assigning it to j.

NestedLoops2 of tutorial9 has a similar cursr shuffle. One point of interest is the loop initiation takes place in a single expression:

j = (sorter = i - 1),

This takes advantage of the fact cursor, when assigned a value, returns that value.

Next...

Next up is the subject of axiom choice which has many useful nuances in it's usage.