Skip to content

APL Array Notation

PhilLast edited this page Sep 3, 2019 · 37 revisions

Navigate this page:

Overview

APL array notation (APLAN) provides a way to serialize APL arrays and namespaces into text files. In addition, it is designed to be embedded in code, that is it is code, and thus could be built into a future version of the APL interpreter.

APLAN extends standard APL notation by allowing matching parentheses and brackets to spread over multiple lines, imbuing this previously invalid syntax with meaning. Brackets may delimit arrays or namespaces.

Within brackets, line breaks delimit non-scalar major cells of an array or the names and values of a namespace.

Within parentheses, line breaks separate items and the entire contents of the parentheses form a vector.

It follows that with respect to arrays, broken brackets delimit arrays of rank 2 or more, and broken parentheses delimit vectors of any depth.

If no expression within a bracket pair results in an assignment then an array is defined. If every expression within a bracket pair results in an assignment then a space is defined. Within an array definition any item may be a space or an array. Within a space definition each expression defines a member. Within a space definition any member may be an array or a space. Within an array definition APLAN does not permit assignments. Within a space definition APLAN does not permit unassigned expressions.

An array is specified by listing out its major cells (sub-arrays) recursively.

Traditional APL literals are valid in an APLAN array, but APLAN is not traditional APL. APLAN is integrated with traditional APL in that any sub-array of an APLAN array may be traditional APL, and vice versa. In other words, APL array notation and APLAN notation can be mixed and matched.

If an array or sub array can be represented in traditional APL as a literal, it may and often should be.

Specification

value:      scalar | list | array | space
scalar:     number | character | space | ⊂ value
number:     as defined for APL
character:  as defined for APL
space:      [ ⋄ pair ⋄ ... ]
     :      [   pair
                ...  ]
pair:       name ← value
name:       as defined for APL
list:       ( ⋄ value ⋄ ... )
    :       (   value
                ...   )
array:      [ ⋄ cell ⋄ ... ]
     :      [   cell
                ...  ]
cell:       list | array | space
n.b an empty space is notated as: [ ⋄ ← ]

Examples

A vector of numeric vectors is easy in APL:

      (1 2 3)  (4 5)  (6 7 8 9)

But if lengthy, may be more readable in APLAN:

      (1 2 3
       4 5
       6 7 8 9)

The line breaks separate the major cells of the 3-item vector. Note that there is an implicit enclose of each item.

A vector of character vectors is easy in APL:

      'Paul' 'Phil' 'Norbert'

But if lengthy, may be more readable and maintainable in APLAN:

      ('Paul'
       'Phil'
       'Norbert')

A one item vector of character vectors is not possible in APL without a function, but in APLAN is:

      ('Joe'
      )

Deeply nested vectors may be done in APL:

      ('US' ('Norbert' 'Paul')) (('UK') ('Phil' 'Kai'))

or in APLAN:

   
      (('US'
        'Norbert' 'Paul')
      ('UK'
        'Phil' 'Kai'))

A matrix has no literal representation in APL, and must be done in APLAN:

      [1 2 3
       3 4 5
       7 8 9]

The major cells (rows) may be any type of vector:

      ['Phil' 1
       'Paul' 2
       'Norbert' 3] 

A cube is a matrix of matrices and thus:

      [[1 2
        3 4] 
       [5 6
        7 8]]

That is, a rank 3 array is a matrix of rank 2 arrays, and thus starts and ends with 2 brackets. A rank 4 array is a matrix of cubes, and thus begins with 3 open brackets. A rank n array begins with n-1 open brackets, and closes with n-1 closing brackets.

Any rank n array may be written as a vector of rank n-1 arrays by replacing the outer brackets with parentheses. Thus the above cube may be converted to a vector of matrices:

      ([1 2
        3 4]  
       [5 6
        7 8])

In fact, the parentheses are redundant if we remove the line breaks between the major cells:

   [1 2
    3 4][5 6
         7 8]

because strand notation applies to APLAN arrays, just as it does to traditional APL arrays. Consider the matrix:

      [1 2
       3 4]

and the vector of character strings.

      ('Kai'
       'Phil'
       'Norbert')

We may place these side by side, using strand notation to create a two-item vector:

      [1 2
       3 4]('Kai'
       'Phil'
       'Norbert')

or using diamonds:

      [1 2⋄3 4]('Kai'⋄'Phil'⋄'Norbert')

Of course once we put the vector of vectors on one physical line there is no reason to not make it a traditional APL array:

      [1 2⋄3 4]('Kai' 'Phil' 'Norbert')

Notice there is no line break between the closing bracket and the opening parenthesis. We could eliminate the strand notation and create a single APLAN array by enclosing the entire array in parenthesis and adding a line break between the two major cells:

      ([1 2⋄3 4] ⋄ ('Kai' 'Phil' 'Norbert'))

Tips and Tricks

A shape 1, depth 2, vector of character vectors is:

     ('Paul'
     )

A matrix with one column containing character strings is thus:

      [ 
        ('Paul'
        )
        ('Phil'
        )
        ('Norbert'
        ) 
      ]

Edge Conditions

Empty arrays and gratuitously enclosed items require special care to specify. These cases are handled by the reshape and enclose primitives respectively.

Namespaces

A namespace:

[
 FirstName←'Paul'
 LastName←'Mansour'
 City←'Key West'
 State←'FL'
]

A vector of namespaces:

([
 FirstName←'Paul'
 LastName←'Mansour'
 City←'Key West'
 State←'FL'
]
[
 FirstName←'Norbert'
 LastName←'Jurkiewicz'
 City←'Austin'
 State←'TX'
])

A namespace of namespaces:

[ Paul←[
        FirstName←'Paul'
        LastName←'Mansour' 
        City←'Key West'
        State←'FL'
       ]

  Norbert←[
           FirstName←'Norbert'
           LastName←'Jurkiewicz'
           City←'Austin'
           State←'TX'
          ]
]