Monday, February 16, 2009

The other APL fan I know

Just when I thought I was the last of a dying breed of APL fans, a coworker encourages me to continue pursuing my interest in APL. Here's an email I received from him....

The example with English words in place of digraphs was in Q, which is a skin over K, another descendant of APL.

http://www.jsoftware.com/jwiki/Doc/J4APL indicates that APL is definitely NOT in 1-1 correspondence with a subset of J.

http://home.earthlink.net/~swsirlin/apl.faq.html gives a fair sized list of APL implementations, some apparently free for Linux but I don't know how complete any of them are.

Good luck on the APL in Python embedding!

Sunday, December 18, 2005

Constructor function for class AplArray

The constructor function of the AplArray class takes a scalar or vector value is input. Scalars are input as a single int, float, or single character str. Vectors are entered as a Python list. Only one dimensional arrays (vectors) of primitive data types are handled properly by the constructor. Reshaping can be handled by a wrapper function. With some work, the constructor should accept nested arrays.


class AplArray:
def __init__(self,data):
if type(data)==list: # Handle list data.
self.shape = [len(data)] # List data only handles scalars
self.data = data # for now.
for item in self.data:
if (type(item) not in [int, float, str]):
print("Invalid Data Type") # Need an exception.
elif type(data)==str: # Handle str or char data.
self.data = data
self.shape = [len(data)]
if self.shape == [1]:
self.shape = []
elif type(data)==int: # Handle integer scalar.
self.data = data
self.shape = []
elif type(data)==float: # Handle float scalar.
self.data = data
self.shape = []
else: # Need an exception.
print "Invalid data type."

Saturday, December 17, 2005

class AplArray

The AplArray class holds array data and shape information. It also defines functions that are fundamental to the array, such as Shape and Reshape. Shape and Reshape will also be defined in the function layer, but will return a different type of object, as will be explained below.

The properties of an AplArray are its shape and data. The shape is always a simple (1-d, non-nested) list. If the data is a scalar, then shape is an empty list. Interestingly, if the data is an empty list, then the shape is [0]!

The data is stored either as an int, float, single-character string, multi-character string, or a list. An int or a float is always a scalar, with shape []. A list or multi-character string has a shape of at least one dimension. Note that a single character string can have either no shape [] or a finite shape. In APL2, the user can enter a single character as a scalar or as a single element array. Python treats single characters as a single character array. The only way to distinguish the shape is by examining the shape property.

The AplArray.Shape(self) function simply returns the shape property as a single integer or list of integers.

The AplArray.Reshape(self,newshape) function reshapes the AplArray with newshape, a list of integers. The data array is shortened or lengthened so that the total number of elements is just enough to fill the shape. The data list itself remains a simple Python list.

The Shape and Reshape functions are defined in the AplArray class layer because these functions are fundamental to the shape and contents of the array. Here, these functions return Python lists (or scalar data) so that they can be directly manipulated with Python functions. These functions will also be implemented as static functions in the function layer of the APyL2 implemented. At the function layer, the Shape function will return an AplArray object.

A few other functions may have to be implemented at the AplArray class level as well, but these will be limited to functionals fundamental to the shape and contents of the array. For example, certain specification operations may want to be implemented here. In any case, any APL intrinsic function that is implemented at the AplArray class layer will also be implemented in the function layer.

Friday, December 16, 2005

Layers of Implementation

APyL2 can be implemented in several layers:


  1. AplArray class with fundamental array structure and behavior
  2. primitive functions that act on AplArray objects
  3. primitive operators that act on functions and AplArrays
  4. symbol name to function name translation functions
  5. APL2 input parser
  6. APL2 character set and interpreter environment


The AplArray class should convert conventional data structures (Python primitives or a Python list) and save the data in a format with characteristics of an APL array. The AplArray should have two Python lists containing the shape of the array and the data in the array. AplArray should also have a basic assignment function which populates the shape and data lists.

The second layer is a set of functions that implements APL2 primitive functions. In IBM's APL2 Programming: Language Reference, Appendix A, there is a table of symbols, symbol names, and function names. These function names can serve as the APyL2 function names. All of these functions will take one or two AplArrays as input parameters and all of them will return either nothing or an AplArray. Examples of function names are Shape, Interval, and Ravel.

The only complicating factor in implementing primitive functions is functions with Axis specification. Axis specification may be an optional input (with an appropriate default set in the function call) for these special functions.

I'm not familiar enough with primitive operators to have a clear idea of how to implement them. My general idea is that primitive operators should be implemented as Python functions which accept primitive functions and arrays as input.

Most APL programmers will recognize symbol names more easily than function names. For example, the symbol name "iota" is easier to remember than the function names "Interval" or "Index Of", which are represented by the iota symbol. Thus, it will be useful to have a symbol name to function name translator that allows the users to call functions by their symbol name rather than by function name. The symbol name to function name translater functions will take one or two AplArrays as input, then pass them to the corresponding monadic or dyadic function associated with that symbol.

The final layer is the APL2 interpreter environment and character set. This is really a user interface layer. All functions, operators, and symbol names can be called by their Python function names in the Python environment. For a complete APL2 experience, however, the APL2 interpreter environment is a necessity.

Thursday, December 15, 2005

The Objective: A Complete Implementation of APL2 in Python

I first heard about APL in the late 90's. I was told by some coworkers about this great programming package written in APL that would only run in a mainframe terminal. I ignored it at first, but then one thing led to another and I got an account on the company mainframe. Then I read "APL is Easy!". Then I read "APL2: At a Glance". Then I was hooked.

I was sad to see how the use of APL is shunned without serious consideration, but I kept using it because, well, it's still useful! There are some operations that are simply easier, quicker, and require less thought in APL than in any other language! I often fire up APL2 when I need to rearrange data from blocks to columns, or extract a column from a text data file. It's also great for multidimensional data. There are other languages (like Python and Matlab) that make it easy to store multidimensional data, but no other language comes close in processing multidimensional data (Matlab is a distant second for anything beyond 2 dimensions).

At work, I use IBM APL2 on Sun Solaris and Linux. At home, I use IBM APL2 Entry Edition for OS/2 and TryAPL2. To buy a modern version of IBM APL2 for personal use will cost me over $1,500.

In my pragmatism, I did start exploring other languages, and I came to appreciate Python. I still prefer programming APL2 or ReXX/NetReXX, but an idea started to gel in my head that a Python implementation of APL2 would give me the best of all worlds.

So, my objective is to create a complete implementation of APL2 in Python.