Post Reply 
newRPL - Updated to build 1510 [official build remains at 1487]
09-08-2021, 03:10 PM (This post was last modified: 09-08-2021 03:14 PM by Claudio L..)
Post: #182
RE: newRPL - Updated to build 1497 [official build remains at 1487]
(09-07-2021 06:07 PM)JoJo1973 Wrote:  I'd like to submit my entry for the Suggested Command of the Month© contest... an implementation of the Check&Dispatch structure!

As we all know, all RPL variants encourage a bottom-up approach to programming and this means that usually there is a main program that crunches the input data to ensure it is valid before calling the actual subroutines.

The problem is that this task can become incredibly boring and convoluted, especially if the objective is to write a library. The simple task to check for three arguments on the stack being a list and two positive integers robs the programming of half the fun!

To ease the burden nothing beats the elegance of SystemRPL's Ck&Dispatch structure which I propose to implement in NewRPL as follows:

Code:

CHECK
    { arglist1 } THEN
        ...
    END
    { arglist2 } THEN
        ...
    END
    .
    .
    .
    ELSE
        ...
    END
END
Each arglist is a list of real numbers, where positive ones are compared against the output of TYPE (if integer) / TYPEE (if they have fractional part), negative one against the output of VTYPE/VTYPEE and 0's are just placeholders meaning "any type".

The check mechanism would retain SystemRPL behaviour wrt tagged objects: the arguments are checked twice; in the first pass tagged objects trigger a match only if arglist explicitly requires a tagged object; in the second pass the tags are stripped and the payload is checked to trigger a match.

It's not mandatory for the arglists to have the same length: the first valid match is dispatched.

The ELSE clause is optional: the default behaviour is "Bad Argument Count" in case of total mismatch or "Bad Argument Type" if at least there is a count match.

Some arglist examples:
Code:

{ } THEN 'SUB0' XEQ END                   @ No arguments: trivial but legal

{ 0 0 0 } THEN 'SUB1' XEQ END             @ Three items on the stack, no matter their type

{ 62 10 } THEN 'SUB2' XEQ END             @ A list and a real number (any kind of real: integer, not integer, exact, approximate, binary, hexadecimal...)

{ 52 10.22 10.33 } THEN 'SUB3' XEQ END    @ A matrix and two real numbers, an approx octal and an exact hex

{ -62 0 10.12 } THEN 'SUB4' XEQ END       @ A variable containing a list, a generic object
                                          @ and a real number, integer and exact
Of course the CHECK..END structure isn't necessarily used to call other programs:
Code:

«
  CHECK
    { 62 } THEN
      « CHECK { 10.12 } THEN DROP 1 END ELSE DROP 0 END »
      1
      DOLIST
      ΠLIST
    END
    { -62 } THEN
      DUP RCL
      « CHECK { 10.12 } THEN DROP 1 END ELSE DROP 0 END »
      1
      DOLIST
      ΠLIST
    END
  END
»
Returns 1 if the argument is a list (or a variable storing a list) of undetermined size containing integer, exact elements and 0 otherwise. I'm assuming here that CHECK doesn't 'consume' the stack.

The arglist concept could also be useful during library creation: at the moment the programmer must provide the number of parameters; instead it could provide a "list of arglists" albeit with the limitation that they must have the same size to comply with NewRPL programming practices.

The beauty is also that as long as sub-type identification becomes smarter, CHECK..END becomes more powerful.

What do you think?

Looks nice and clean! But maybe we can reuse the CASE structure with some clever commands and not introduce another complex flow control structure into the language.
On another hand, the CK&Dispatch method almost never worked for me in real life, except for very simple commands.
You end up with situations where 5 or 10 cases are needed for the same basic code, then other 5 or 10 for another, etc.
A very simple example, some code takes 1 argument: can be a real or a complex. Your code works the same whether is a real or complex, all you need is a "numeric". Also you may accept the complex i constant (which has a different type but it's 100% equivalent to (0,1)), so you'll end up with 3 argument list cases for the exact same code. Now let's imagine one that takes 2 of these arguments. Your list cases will need to cover all combinations: real/real, real/complex, real/i, complex/real, complex/complex, complex/i, i/real, i/complex, i/i.
So it explodes into a nightmare really easily. It would be OK if you needed different code for each case, but in most cases you don't.
What I find works better for me is to check the arguments one by one, and each argument against a list of valid types, not just one type.
Something like:
Code:

1 { 10 30 55 } ARGCK
In this case, ARGCK takes a stack level and a list of valid types. It will error Bad Argument Type if there's no match, or continue execution if everything is fine. There could also be a version that doesn't error but returns true/false for example, to be used in IF or CASE statements.
In the example above with 2 arguments, you could simply do them in sequence:
Code:

1 { 10 30 55 } ARGCK
2 { 10 30 55 } ARGCK

If it didn't error, you have the right types. Now let's say some cases need special handling, in the example above we may want to convert the constant 'i' into a complex number by doing ->NUM, and perhaps accept other things like a complex number in symbolic form '1+i'.
Let's say we create the ARGCKTF command (ARG ChecK True/False, I'm open to better name suggestions) that doesn't error, we can use IF to simply do ->NUM and try again:
Code:

IF 1 { 55 32 56 } ARGCKTF THEN ->NUM END
1 {10 30 } ARGCK

So we check first if argument 1 is a constant, a variable identifier (because, why not?) or a symbolic and we run ->NUM. After that, we check that we ended up either with a real or a complex number, and error if not.

This is some hybrid between what Bruce proposed (one compact command that errors if there's no match), your proposal using a list of TYPE/TYPEE numbers and my own spin checking arguments one by one in sequence rather than in bulk.

Can you think of cases where these 2 commands would fail to work well?

**EDIT**: By the way, if the depth of the stack is less than the argument number you passed to ARGCK, then it will error Bad Argument Count so that case is covered and you never need to provide an argument count.
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: newRPL - Updated to build 1497 [official build remains at 1487] - Claudio L. - 09-08-2021 03:10 PM
Navigating through sub-menus - Gilles - 05-13-2023, 11:31 AM
It's a mystery to me... - Klaus - 11-27-2023, 12:24 PM



User(s) browsing this thread: 4 Guest(s)