After a short break, work has resumed in newRPL. The most notable addition is algebraic objects. Expressions can now be compiled/decompiled properly, including variables, all operators and functions of variable number of arguments. This all puts newRPL symbolic capabilities roughly at the level of the HP48 (in the sense that expressions can be written, operated upon, and evaluated but there's no CAS).

Where to go from here? A new CAS needs to be written. While there are open source CAS systems available, none can integrate with the RPL framework very well. As of right now, a rule matching engine is in the works (it can match some basic rules already). Rules are one of the many ways to implement a CAS, and being an open approach it was the chosen route.

The idea is that many of the commands in userRPL that make use of the CAS are more or less substitution rules, so a generic engine would allow to implement a large fraction of the commands just by creating a list of rules.

Rules use a new operator in newRPL, which combined with specially formed placeholder IDENTS will provide a functionality similar to "large" CAS systems.

For example:

<< 'X+1' 'X->Z+1' RULEAPPLY >>

will produce

'Z+1+1'

While simple substitutions like this one can be accomplished simply by storing 'Z+1' in the variable 'X' and using EVAL, the engine allows generic IDENTS that are placeholders for complex expressions. These special IDENTS begin with a dot, and are to be used only in rules:

<< 'X^2-(X+2)^2' '(.A+.B)^2->.A^2+2*.A*.B+.B^2' RULEAPPLY >>

will interpret the generic identifiers '.A' and '.B' as any expression, and make the replacements:

'X^2-(X^2+2*X*2+2^2)'

There are additional constraints that can be included in the name of the variable, for example '.A.N' will match only numeric expressions (any expression that does not contain any IDENTS).

The command RULEAPPLY will accept single rules, lists of rules, or a variable name containing a list of rules or a rule.

There will be system rule lists for the most common operations, and the user will be able to override, or add to the rules. For example (and this is subject to change), the comand SIMPLIFY could use a system list of rules, and then look for a variable named 'RULES.SIMPLIFY' in the current directory. If the variable exists, also apply those rules.

This mechanism will allow users to customize and expand the CAS with their own rules, which will be used automatically by the usual commands.

Work on this rule matching engine is delaying the release of the next demo, which will include basic rule replacement functionality.

The core keeps progressing at a steady pace. Almost all commands dealing with lists are complete now. Also basic support for complex numbers was added, including all operators.

The compiler was modified this week after a few months of stability: the ability to automatically split tokens was added, allowing more flexibility in data input. Now lists can have the delimiters immediately before or after an element, with no blanks in between, so that:

{1 2 3} = { 1 2 3 }
{} = { }
{{{1}}} = { { { 1 } } }

This is how it works in the original RPL implementation, so it is expected that users will want to continue using the same practice.

Complex numbers can be introduced with or without blanks as well:

(0,1) = ( 0 , 1 )

(0 1) = ( 0 , 1 )

This is the first step for the compiler to accept infix notation. Time has come to add symbolics,which may require extensive changes.

Stay tuned for an updated demo with these new features.

The demo was updated to revision 0.2-alpha. It contains many bugfixes and reliability improvements, especially in the transcendental functions, and a more consistent behavior with regards to the scoping and evaluation of local and global variables.

Variables are now more consistent:

* A variable identifier that is unquoted in a command will look first for a local variable with that name (first in the current secondary, then defined by parent secondaries), and if not found it will look for a global variable (first in the current directory, then in parent directories). The contents of the variable will be evaluated.

* Using LRCL on a variable name will only look for local variables, either from the current secondary or its parents. The contents will not be evaluated.

* Using RCL on a variable name will look for locals first, then global variables, just like unquoted names, except the contents will not be evaluated.

This allows the creation of local variables to "shadow" global variables. For example, a program that is known to write to global variables X and Y, can be "sandboxed" by creating local variables X and Y in a parent secondary that calls the program.
 

* Storing to a local variable with LSTO will check if the variable was defined in the current secondary. If not, it will create a new local variable with the same name that will "shadow" any variable with the same name (either defined locally in a parent secondary, or globally in the current dir or parents), from that point on.

* Storing to a global variable (with STO) will check if the variable is defined in the current directory. If not, it will create a new variable in the current directory.

* Storing to a global variable (with STO) that was "shadowed" by a local variable in a parent secondary will overwrite the value of the local variable in the parent's environment. This is so that the parent secondary can use the value of the variable, as modified by the inner program.

This mode of operation slightly more powerful than the original model in userRPL (where local variables were not visible to child programs unless explicitly defined as "compiled" variables in the child program) since it allows sandboxing, while at the same time remains compatible. The child program doesn't know that is reading/writing to a shadowed variable. Once the parent secondary ends, the variables vanish, leaving the directories clean.

On the other hand, programs that are designed to be encapsulated can use LSTO/LRCL, which will never modify its parents variables, even if they are defined with the same name.

The EVALuation of variables has also been modified. Evaluating a variable name that contains a variable name will leave it on the stack, rather than evaluating it recursively. This allows for "step-by-step" evaluation (doing EVAL repeatedly) and a more consistent manipulation of symbolic expressions in the future.

The only new command introduced with this demo is DOLIST. Other list processing commands are in the works.

The first alpha-0.1 demo was released today for Windows platforms, with other platforms to follow in short.

A few things to play with

Variable precision:

SETPREC

The SETPREC command will take an integer from the stack, the number of significant digits for operations. Any number form 1 to 2007 is acceptable.

LSTO/LRCL

These commands are STO/RCL but for local variables. Local variables can be created anywhere in the code without anything special. Just use LSTO, and the variable wil exist until you exit the current environment (be it a loop, or a secondary, etc)

Bear in mind that this early demo has no display capabilities, so it will display raw numbers (all the digits that the number has stored in memory, and shown "as-is"). That means some ugly representations are possible, like 30 being shown as 3E+1, or integer numbers shown as 3.00000000. This is normal since there are no proper output routines yet.

Soon we'll have a table showing what commands are currently implemented. For now, if any command shows as a variable name on the stack, it means is not implemented yet.

The commands that are currently implemented are:

Transcendentals: LN, EXP, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, SINH, COSH, TANH, ASINH, ACOSH, ATANH

Arithmetic: All operators and SQRT for the square root.

Lists: GET, PUT, GETI, PUTI, HEAD, TAIL, ->LIST, OBJ->

Loops: All commands supported

Flow control: All commands supported

Stack: CLEAR, DUP, DROP, SWAP, ROT, UNROT, PICK

Precision: IP, FP, SETPREC, FLOOR, CEIL

Directories: CRDIR, UPDIR, HOME, PGDIR

Variables: RCL, STO, LRCL, LSTO, INCR, DECR, PURGE