[comp.sys.handhelds] RPL Code for Lists/Sets, Rev 2

dan@Apple.COM (Dan Allen) (04/11/90)

                    LIST and SET Operations for the HP-48SX
                         By Dan Allen, 10 April 1990
                                Revision 2

LIST PROCESSING
  The HP-48SX supports lists of objects as a built-in data type.  Several 
functions are provided for working on lists:

    Function     Operation
    --------     ---------
    +            Concatenates two lists into one list
    SIZE         Returns the number of elements in a list
    POS          Checks if an element is in a list
    SUB          Returns a subset of a list as a list
    GET          Returns the nth element of a list
    PUT          Replaces the nth element of a list

Other than direct editing of a list, there is no way to add elements to a list 
other than by appending elements to the front or back of a list through the + 
operator, and there is no way to delete elements of a list.
  Here are a few list operations that extend the functionality of the HP-48SX.  
Ideally these should be in a future machine; in the meantime they should be 
written in assembly language for better efficiency.
  The first two functions are CAR and CDR, named after the LISP functions of 
the same bizarre but historically interesting names.  Common LISP also has the 
functions FIRST and REST which are exactly the same as CAR and CDR, which 
return the first and remaining parts of a list.  The second pair of functions 
are INS and DEL, which allow inserting and deleting specific elements of a 
list.
  These routines handle invalid arguments quietly, i.e., deleting the 5th 
element of a 4 element list does nothing; it returns the 4 element list 
unchanged, without any error mentioned.  Similar handling of invalid 
conditions is done by the other routines as well.

LISTS AS SETS
  A list supports an ordering of its elements and can have duplicate members.  
Sets are not ordered and can only have one occurance of a given object.  With 
these restrictions, a list can be used as a set with various functions 
designed to support set operations.  Such functions are provided here, with 
many of the operations also being valid on lists as well.
  ADJOIN allows items to be added to a set.  ADJOIN makes sure that no 
duplicate entries are allowed in the list, thus enforcing one of the rules of 
sets.
  MEMBER tests set membership, that is, it checks to see if an object is 
included in a set (or list).  It only searches the top level.  It returns a 
CDR-like list beginning with the item found, or the empty list { } if the 
object is not found.
  UNION and INTERSECT implement set union and intersection, while DIFF and 
SDIFF are set difference and symmetric difference.  If the lists given are not 
sets (that is, they contain duplicates), duplicates may appear in the results.  
These four operations are the main arithmetic operations for sets, with the 
following similarities to arithmetic and boolean operations:

   ARITHMETIC            BOOLEAN            SET OPERATION
   ----------            -------            -------------
   addition (+)          OR (inclusive)     union
   subtraction (-)       AND NOT            difference
   multiplication (*)    AND                intersection
   division (/)          XOR                symmetric difference

EXAMPLES

{ 1 2 3 } CAR  -->  1                 { } CAR  -->  { }
{ 1 2 3 } CDR  -->  { 2 3 }           { } CDR  -->  { }

{ 1 2 3 } 1 0 INS  -->  { 0 1 2 3 }   { 1 2 } 9999 48 INS  -->  { 1 2 48 }
{ 1 2 3 } 2 DEL  -->  { 1 3 }         { 1 2 } 9999 DEL  -->  { 1 2 }

{ 1 2 3 } 2 MEMBER  -->  { 2 3 }      { 1 2 3 } 4 MEMBER  -->  { }
{ 1 2 } 3 ADJOIN  -->  { 1 2 3 }      { 1 2 3 } 3 ADJOIN  -->  { 1 2 3 }

{ 1 2 } { 3 4 } UNION --> {1 2 3 4}   { 1 2 } { 1 2 } UNION  -->  { 1 2 }
{ 1 2 } { 3 4 } INTERSECT --> { }     { 1 2 } { 2 3 } INTERSECT  -->  { 2 }
{ 1 2 } { 3 4 } DIFF --> { 1 2 }      { 1 2 } { 2 3 } DIFF  -->  { 1 }
{ 1 2 } { 3 4 } SDIFF --> {1 2 3 4}   { 1 2 } { 2 3 } SDIFF  -->  { 1 3 }

  Comments are bracketed by @ signs.  With minor changes, most of these 
programs should run on the HP-28.  Here then are some useful list and set 
operations for the HP-48SX:

CAR   @ Extracts the first object of a list as an atomic entity @
<<    @ USAGE:  list CAR  -->   obj   @
  IF DUP SIZE THEN 1 GET END  @ CAR of empty list is an empty list @
>>

CDR   @ Returns the tail (all but 1st object) of a list as a list @
<<    @ USAGE:  list CDR  -->  list   @
  OBJ->
  IF DUP
  THEN 1 - ->LIST SWAP DROP
  ELSE DROP { }   @ CDR of an empty list is the empty list @
  END
>>

INS   @ Inserts an object as the nth element of list @
<<    @ USAGE:  list integer obj INS  -->  list   @
  -> list n x
  <<
    list 1 n 1 - SUB x + list n list SIZE SUB +
  >>
>>

DEL   @ Deletes the nth element of list @
<<    @ USAGE:  list integer DEL  -->  list   @
  -> list n
  <<
    list 1 n 1 - SUB list n 1 + list SIZE SUB +
  >>
>>

MEMBER  @ Checks if obj is a member of list at the top level @
<<      @ USAGE:  list obj MEMBER  -->  list   @
  -> list obj
  <<
    list obj
    IF POS DUP 0 >
    THEN list SWAP list SIZE SUB
    ELSE DROP { }
    END
  >>
>>

ADJOIN  @ Adds an object to a list, preventing duplicates @
<<      @ USAGE:  list obj ADJOIN  -->  list   @
  -> list obj
  <<
    IF list obj MEMBER SIZE
    THEN list
    ELSE list obj +
    END
  >>
>>

UNION  @ Returns the set union of two lists (c = a OR b) @
<<     @ USAGE:  list list UNION  -->  list   @
  OVER -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN a b +  @ if either list is empty then concatenate lists @
    ELSE        @ step through the second list's elements @
      b 1 1 b SIZE
      START
        GETI DUP c SWAP
        IF POS
        THEN DROP
        ELSE 'c' SWAP STO+  @ adding appropriate new elements @
        END
      NEXT
      DROP2 c 
    END
  >>
>>

INTERSECT  @ Returns the set intersection of two lists (c = a AND b) @
<<         @ USAGE:  list list INTERSECT  -->  list   @
  { } -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN c
    ELSE
      b 1 1 b SIZE
      START
        GETI DUP a SWAP
        IF POS
        THEN 'c' SWAP STO+
        ELSE DROP
        END
      NEXT
      DROP2 c
    END
  >>
>>

DIFF  @ Returns the set difference of two lists (c = a AND NOT b) @
<<    @ USAGE:  list list DIFF  -->  list   @
  { } -> a b c
  <<
    IF a SIZE 0 == THEN c
    ELSE IF b SIZE 0 == THEN a
      ELSE
        a 1 1 a SIZE
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2 c
      END
    END
  >>
>>

SDIFF  @ Returns the set symmetric difference between two lists (c = a XOR b) 
@
<<     @ USAGE:  list list SDIFF  -->  list   @
  { } -> a b c   @ Efficiency note: this is O(n^2) and could be improved @
  <<
    IF a SIZE 0 == THEN b         @ if a is empty, then return b @
    ELSE IF b SIZE 0 == THEN a    @ if b is empty, then return a @
      ELSE                        @ else loop through both lists @
        a 1 1 a SIZE     
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2
        b 1 1 b SIZE
        START
          GETI DUP a SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2 c
      END
    END
  >>
>>