Post Reply 
Programming puzzles: processing lists!
05-02-2017, 07:00 PM
Post: #63
RE: Programming puzzles: processing lists!
The challenges for #2 and #12 are simple enough that they make good examples for multiple languages. I thought I'd show one approach to that type of problem using SysRPL, though this example doesn't use the built-in list processing features.

First, some general considerations:

1) One of the great benefits to SysRPL programming is a speed improvement realized from using type-specific commands that don't waste time checking their arguments first. There is a risk, though. Passing the wrong type of argument to a command doesn't usually end well, and will likely cause a crash and possibly the loss of data. Type checking that may be considered a luxury in UserRPL isn't optional with SysRPL.

2) SysRPL commands can't be entered into a program using the same "<< command1 command2 ... >>" structure that UserRPL uses on the calculator. The code has to be compiled into a single object before it can be used, and there are several ways to do this. My preferred way is to write and compile the code on a computer using Debug4x, then transfer it to the calculator after debugging it. So the example below uses the syntax appropriate for that particular scenario.

3) SysRPL is still RPL. A running SysRPL program uses the stack and other calculator resources in the same ways that UserRPL does. So items are placed on (and removed from) the stack in the same ways that you are already used to seeing them. There are simply more commands available that work in slightly different ways than you may be used to seeing.

To help with reading the code, here's a couple of hints about some specifics:
- a SysRPL "LAM" is the equivalent of a UserRPL local variable. I've used a particular type of LAM here known as a "NULLLAM", which is accessed via an index number instead of a name. They are one of the best things about SysRPL IMHO because they allow you the benefits a local variables with notable speed improvements over named locals. For readability, I DEFINEd a "substitute" for the 1GETLAM SysRPL command to make it more clear what was actually happening.
- numbers in RPL can be REAL (which always have a fraction mark) or INTEGER (which never have a fraction mark). In SysRPL, integers of this type are called ZINTs.

Enough of that. Here's my liberally-commented version of a SysRPL solution to challenge #12:
INCLUDE DirMacro.s

   Dir <Ch1203>

( local variable DEFINE for readability )
DEFINE   GetListSize    1GETLAM

   CK1NOLASTWD          ( program needs at least 1 object on stack )

   CK&DISPATCH1         ( dispatch to the appropriate block based on type of object )

   list ::              ( this block applies if SL1 object is a list )
      INNERCOMP         ( explode the list )
      DUP1LAMBIND       ( make a copy of the size then bind it to NULLLAM #1 )

      #1+_ONE_DO (DO)   ( do for each element in the list )

         DUPTYPEREAL? IT ::            ( only do if object is a REAL )
            %3 OVER %= casedrop %5     ( 3 becomes 5 )
            %5 OVER %= casedrop %3     ( 5 becomes 3 )
         ;                             ( any other REAL is ignored )

         DUPTYPEZINT? IT ::            ( only do if object is a ZINT )
            Z3_ OVER Z= casedrop Z5_   ( 3 becomes 5 )
            Z5_ OVER Z= casedrop Z3_   ( 5 becomes 3 )
         ;                             ( any other ZINT is ignored )

         ( any other object type is ignored )

         GetListSize ROLL  ( roll the entire list on the stack )
      LOOP                 ( end of DO loop )

      GetListSize {}N      ( implode the list )
      ABND                 ( release NULLLAMs )

This above SysRPL implementation was meant to be the functional equivalent of this UserRPL program:
  DUP \-> listSize
        3 OVER == THEN DROP 5 END
        5 OVER == THEN DROP 3 END
      listSize ROLL
    listSize \->LIST

I didn't use DOSUBS in this case in order to provide for a more direct comparison.

There's a couple of notable benefits that the SysRPL implementation provides:
- A well-formed SysRPL program should always check for appropriate stack contents when it starts. Not doing so can (and probably will) result in a crash. So this program provides meaningful checking of its argument, and will exit gracefully with an appropriate error if a list isn't in stack level 1 upon entry.
- The program flow differentiates between REAL and INTEGER elements and provides the translation of the numbers accordingly. This could also have been done using UserRPL, of course, but it was an easy add to the SysRPL version since I had to check the type anyway. I didn't bother to do that with the UserRPL version.

So what about performance?

Readability is subjective, but I believe the SysRPL version is at least as readable as the UserRPL version, at least to someone familiar with the language constructs.

The UserRPL version may look smaller than the SysRPL version, but that's probably due to the lack of comments and tighter spacing. The actual size of the SysRPL version is 110 bytes, as compared with 127 for the UserRPL version. The UserRPL version could have saved some bytes by using a shorter local variable name, at the cost of readability. One of the size benefits of SysRPL is that there are many "combo" commands that do multiple steps while only taking up 5 nibbles.

Speed is probably the best benefit here. The extra time taken by nearly all UserRPL commands to validate their arguments adds up during the execution of a program, especially when loops are involved. For this test I used the average of 50 iterations of lists containing 200 elements. Here's how the two versions performed:

UserRPL version: 1.878 seconds/list
SysRPL version: 0.386 seconds/list

Not too shabby!
Find all posts by this user
Quote this message in a reply
Post Reply 

Messages In This Thread
RE: Programming puzzles: processing lists! - DavidM - 05-02-2017 07:00 PM

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