Skip to content

Workspace Listing in I-APL

Vector 9:1, page 32

programming techniques education

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 32

It is interesting once in a while to see the content of a workspace: the lists of variables and functions and their size and content.

)VARS, )FNS, ⎕WA, ⎕LX and the Del editor (∇) or ⎕CR will provide the information but there is no record. It is also handy to have a file with the printed content of the workspaces, for example to be able to copy a function into another workspace.

We will create a LIST utility workspace which can be copied into a working workspace, used to print the content and then be discarded.

As with all workspaces, but especially here with the utility workspace, great care should be taken to avoid conflict of names.

The names of the variables, functions and local variables will be systematically prefixed with ∆ or ∆∆. Recall that ∆, and _ can be used in names (N.B. ∆ can even be used alone in I-APL — I often use ∆ alone for the WHERE function, ∆:⍺, creating a kind of diamond separator and providing shorter lines which fit in the 79 characters length of line of I-APL). Another way would be to use lower-case letters; they can be typed in using the <INS> key: first press <INS> (this switches the keyboard to lower-case), input your text and press <INS> again to return to the normal keyboard.

The use of ∆ for the names allows the creation of normally unused names to avoid conflict with the names of the objects of the workspace to be listed. In particular, if objects in the workspace are called A, B, C, … and if we use these names as local variables in our listing functions, the content of the objects will not be printed but instead the present content of the local variables. The same conflict can arise with the local variables of functions and subfunctions.

A main function, ∆GO, will initialize some local variables (∆CR carriage return, ∆LF line feed and ∆FF form feed) and will call a function to print headings to the report (∆∆HEADINGS) and a function managing the printout of the content (∆∆WSPACE). The argument of ∆GO is the name of the workspace; other information is passed in global variables:

∆WA  ← ⎕WA        ⍝ free space
∆V   ← ⎕NL 2      ⍝ variables list
∆F   ← ⎕NL 3      ⍝ functions list

It should be noted that ∆V will contain ∆WA, so we will take off ∆WA from ∆V in ∆GO.

∆∆HEADINGS prints the title of the workspace which is supplied to ∆GO and passed as argument to ∆∆HEADINGS. It also prints the content of the Latent Expression (⎕LX) and the space used by the workspace. This last value is computed as the difference between the available space of an empty workspace (on my PC 31,644) and the ⎕WA of the current workspace supplied as the global variable ∆WA.

∆∆WSPACE first prints the lists of the variables and functions through the ∆∆VARSFNS function and then prints the content of the variables and functions with the ∆∆LIST function.

The ∆∆VARSFNS function lists the names of the variables and functions, six names per line. This restricts the length of the names to 15 characters (for a line of 80 characters). In practice the names are limited to 12 characters which is quite sufficient; only 2 or 3 names were of that length in the workspaces distributed with I-APL (and were placed at the end of the line).

The argument ⍵ (⍵ ← ⎕NL 2 or 3) is first padded with blanks by the primitive Take (in this case it overtakes) and then raveled:

∆A ← 1 ↑ ⍴⍵
 ⍵ ← ,(∆A, 12)↑⍵

60 blanks are added in case the last line does not have six names and the result reshaped to lines of 72 characters and printed.

 ⍵ ← ⍵ ,60 ⍴' '
∆B ← ⌈ ∆A ÷ 6     ⍝ round up for incomplete line
∆B ← ∆B,72
 ⍵ ← ∆B ⍴ ⍵

∆V and ∆F provided to ∆∆LIST the lists required as right argument ⍵; ⍺, the left argument of ∆∆LIST, will specify if ⍵ contains variable names (⍺='V') or function names (⍺='F'). We first check if ⍵ is empty, in which case we do nothing with a branch to 0.

→(0 ∊ ⍴ ⍵)/0

Then in a DO … WHILE loop we take the top name of the list, print the content of the object and erase the name; we repeat the loop while the list is not empty.

NXT:
   ....
   ....
 ⍵ ← 1 0↓⍵
 →(~ 0 ∊ ⍴ ⍵)/NXT

The way to print the content of variables being different from the one for the functions we call a specific function using an IF construct, for example:

⍎(⍺='V')/'∆∆VARIA,⍵[⎕IO;]'

We take the first line: ⍵[⎕IO;] whichever is ⎕IO and ravel it to a vector.

∆∆VARIA prints the name of the variable (and its shape as an extra) followed by its content. To find the shape and the content we have to execute ⍵, argument of ∆∆VARIA, containing the name of the variable.

∆∆PRINT '      ',⍵,'      (dim: ',(⍕ ⍴ ⍎ ⍵ ),')'
∆∆PRINT ⍎ ⍵

∆∆FUNCT only prints ⎕CR ⍵. We will see later some cosmetics for the result.

The printing function ∆∆PRINT has to handle the printing of a matrix, a vector or a scalar. ⍵ is first formatted as characters:

⍵ ← ⍕ ⍵

and then reshaped as a matrix with each line suffixed by carriage return and line feed (this could be printer specific) and printed with ⎕TX:

∆A ← ¯2 ↑ 1 1, ⍴ ⍵      ⍝ reshapes  to a matrix
⍵ ← ∆A ⍴ ⍵              ⍝ of minimum 1 1 shape
⍵ ← ⍵ , ∆CR             ⍝ appends carriage return
⍵ ← ⍵ , ∆LF             ⍝ appends line feed

Cosmetics

⎕CR returns a character matrix of the list of a function but the lines are not numbered. In other systems, the ⎕VR function returns a nicely formatted list of the function:

      ⎕VR 'VARIA'
    ∇ ∆∆VARIA
[1]   ⍝ Prints the content of the variable of name
[2]    ∆∆PRINT '      ',⍵,'      (dim: ',(⍕⍴⍎⍵),')'
[3]    ∆∆PRINT ⍎⍵
    ∇

We can add this extra touch to our function without difficulty. First we create a character variable with the initial ∇ and the line numbers; we will limit ourself to 30 lines.

      ∆∆NUM ← ⍕ 30 1 ⍴ ⍳30          ⍝ 30x3 character matrix of
                                   ⍝ the numbers 1 to 30
      ∆∆NUM ← ∆∆NUM,']'             ⍝ adds closing bracket
      ∆∆NUM ← 1 ⌽ ∆∆NUM             ⍝ suppresses the leading
      ∆∆NUM[⍳9;] ←1⌽∆∆NUM[⍳9;]      ⍝ blanks
      ∆∆NUM ← '[',∆∆NUM             ⍝ adds the opening bracket
      ∆∆NUM ← (1 5 ⍴'    ∇'),[1]∆∆NUM  ⍝ adds the line 0 ∇ symbol
      ∆∆NUM
    ∇
[1]
[2]
[3]
       ...... numbers from 4 to 27
[28]
[29]
[30]

Note that ∆∆NUM could be created ‘on the spot’ in ∆∆FUNCT, but this would slow down the system. We use ∆∆NUM in ∆∆FUNCT[3] to add the numbers to ⎕CR if the function is not a direct definition function. After printing the numbered ⎕CR, we add a closing ' ∇'.

After using the LIST workspace, its functions and variables should be removed. This is easily achieved with the Expunge system function ⎕EX. Before saving the LIST workspace we create a variable containing the lists of names:

      ∆V←''                       ⍝ dummy variables for ∆V, ∆F and
      ∆F←''                       ⍝ ∆WA which should also
      ∆WA←''                      ⍝ be removed
      ∆∆VARL ← ⎕NL 2 3
      ∆∆VARL
∆F
∆GO
∆V
∆WA
∆∆FUNCT
∆∆HEADINGS
∆∆LIST
∆∆NUM
∆∆PRINT
∆∆VARIA
∆∆VARL
∆∆VARSFNS
∆∆WSPACE
      )ERASE ∆V ∆F ∆WA
      ⎕LX← 'This is the LIST workspace'    ⍝ Latent expression
      )SAVE
LIST

Using LIST

Before copying LIST into the current workspace we create the global variables with the free space and the lists of variables and functions:

      ∆WA ← ⎕WA                ⍝ before anything
      ∆V ← ⎕NL 2               ⍝ before ∆F, will contain ∆WA which
                               ⍝ is removed in ∆GO
      ∆F ← ⎕NL 3
      )COPY LIST
      ∆GO 'the name'
           .....                 ⍝ it works!?
      ⎕EX ∆∆VARL                 ⍝ expunge the LIST objects
1 1 1 1 1 1 1 1 1 1 1

Limitations

If the name of a variable or function is longer than 12 characters it will be truncated in the list of names, but not later; if it is 12 characters, it will stick to the next one (unless it is the last name of the line). We have limited the length of functions to 30 lines; this can be adjusted. But who writes functions longer than a screen? If the current workspace is big, there could be a WORKSPACE FULL message. The solution (tedious) is to split it in pieces, for the listing only. To avoid complexity and to reduce the size of LIST there is no provision for the page jump; some lists will be cut. To reduce the size of LIST, all the comments could be removed from the working version. Some variables are impossible to print. This is the case with the FONT variable of the EPSON workspace; it contains control characters for the printer. I replaced it by:

FONT ← 'This is a variable containing the font code'

P.S. A similar function could be created to print in a file instead of on the printer; it should incorporate some of the functions of DFILE, including the opening and closing of the file and ∆∆PRINT should be adjusted.

LIST on LIST

LIST
====

⎕LX ← 'This is the LIST workspace'
Space used: 8704

**********Variables**********
∆∆NUM    ∆∆VARL
**********Functions**********
∆GO          ∆∆FUNCT      ∆∆HEADINGS  ∆∆LIST      ∆∆PRINT     ∆∆TITLE ∆∆VARIA
∆∆VARSFNS    ∆∆WSPACE

      ∆∆NUM       (dim: 31 5)
    ∇
[1]
[2]
[3] ...
[28]
[29]
[30]
      ∆∆VARL      (dim: 11 10)
∆F
∆GO ....
∆∆VARSFNS
∆∆WSPACE

    ∇ ∆GO ⍵;∆CR;∆LF;∆FF;∆A
[1]   ⍝ Main function to list the content of a workspace
[2]    ∆CR←⎕AV[13+⎕IO] ⍝ Carriage return
[3]    ∆LF←⎕AV[10+⎕IO] ⍝ Line feed
[4]    ∆FF←⎕AV[12+⎕IO] ⍝ Form feed
[5]   ⍝ Taking off ∆WA from ∆V
[6]    ∆A←¯1↑⍴∆V
[7]    ∆V←(∆V∨.≠∆A↑'∆WA')⌿∆V
[8]    ∆∆HEADINGS
[9]    ∆V ∆∆WSPACE ∆F
    ∇

    ∇ ∆∆FUNCT ⍵;∆A
[1]   ⍝ Prints the ⎕CR of the function in a mode similar to ⎕VR
[2]    ∆A←⎕CR ⍵
[3]    ⍎(2=⍴⍴∆A)/'∆A←(((1↑⍴∆A),5)↑∆∆NUM),∆A'
[4]    ∆∆PRINT ∆A
[5]    ⍎(2=⍴⍴∆A)/'∆∆PRINT ''    ∇'''
    ∇

    ∇ ∆∆HEADINGS ⍵
[1]   ⍝ Prints headings for the workspace
[2]    ∆∆PRINT ⍵
[3]    ∆∆PRINT (⍴⍵)/'='
[4]    ∆∆PRINT ''
[5]    ∆∆PRINT '⎕LX ← ''',⎕LX,''''
[6]    ∆∆PRINT ''
[7]    ∆∆PRINT 'Space used: ',(⍕31644-∆WA)
[8]    ∆∆PRINT ''
    ∇

    ∇ ⍺ ∆∆LIST ⍵
[1]   ⍝ Successively lists the variables and functions
[2]    →(0∊⍴⍵)/0
[3]   NXT:
[4]    ⍎(⍺='V')/'∆∆VARIA,⍵[⎕IO;]'
[5]    ⍎(⍺='F')/'∆∆FUNCT,⍵[⎕IO;]'
[6]    ∆∆PRINT ''
[7]    ⍵←1 0↓⍵
[8]    →(~0∊⍴⍵)/NXT
    ∇

    ∇ ∆∆PRINT ⍵;∆A;∆B
[1]   ⍝ Prints the matrix, vector or scalar
[2]    ⍵←⍕⍵
[3]    ∆A←¯2↑1 1,⍴⍵
[4]    ⍵←∆A⍴⍵
[5]    ⍵←,∆CR ⍵
[6]    ⍵←⍵,∆LF
[7]    2 ⎕TX ⍵
    ∇

    ∇ ∆∆VARIA ⍵
[1]   ⍝ Prints the content of the variable of name
[2]    ∆∆PRINT '      ',⍵,'      (dim: ',(⍕⍴⍎⍵),')'
[3]    ∆∆PRINT ⍎⍵
    ∇

    ∇ ∆∆VARSFNS ⍵;∆A;∆B
[1]   ⍝ Lists the names of variables and functions
[2]   ⍝ formatting in lines of six names of maximum 12 characters
[3]    ∆A←1↑⍴⍵
[4]    ⍵←,(∆A,12)↑⍵
[5]    ⍵←⍵,60⍴ ' '
[6]    ∆B←⌈∆A÷6
[7]    ∆B←∆B,72
[8]    ⍵←∆B⍴⍵
[9]    ∆∆PRINT ⍵
    ∇

    ∇ ⍺ ∆∆WSPACE ⍵
[1]   ⍝ Prints the content of the workspace
[2]   ⍝ first the lists of variables and functions, then their content
[3]    ∆∆PRINT '**********Variables**********'
[4]    ∆∆VARSFNS ⍺
[5]    ∆∆PRINT ''
[6]    ∆∆PRINT '**********Functions**********'
[7]    ∆∆VARSFNS ⍵
[8]    ∆∆PRINT ∆LF
[9]    'V' ∆∆LIST ⍺
[10]   ∆∆PRINT ''
[11]   'F' ∆∆LIST ⍵
[12]   ∆∆PRINT ∆F