Axis oriented programming
I was reading some APL when I realized I had invented a new style of programming language. It hasn’t been implemented as far as I know. The syntax is just any old syntax. I am trying to be non-cryptic, but if you are planning to implement this, you probably want better, more consistent syntax. This is supposed to be a cool new idea, some bits haven’t been fully thought through. If you are looking for inspiration in designing a programming language, this might be it.
Suppose you are dealing in numpy, and some of your arrays have like 10 or 20 dimensions. And you are finding it really hard to keep track and remember that axis 4 of array foo represents the same thing as axis 7 of array bar. Then array oriented programming is for you.
Conceptually, there are axis and there are data. If you see something like
Axis foo=Axis([5])
Int a=1
Axis bar=Axis([6])
Float b=bar.index.as_type(float)
Every variable like a and b can be imagined as actually being an array, with a dimension for every axis. There is no such thing as a constant, just an array that happens to be constant. [5] represents the type of numbers that are non-negative integers < 5. Ie 0,1,2,3,4.
bar.index is an array of type [6], which can be typecast to float.
A naive compiler/ interpreter for this language would soon find every object becomes an exponentially large array as soon as more than a few Axis are created. Its the compilers job not to be that naive. It shouldn’t store fast grids of the same number over and over. A good compiler might use all sorts of tricks, like lazy evaluation, and https://en.wikipedia.org/wiki/Matrix_chain_multiplication to reorder operations. These are implementation details.
Simple functions using axis
Lets look at a few functions.
Sum:[Axis] -> Float -> Float
Takes the sum of the inputted array along the Axis. Places this value in every position in the array. The axes used must implement the summable characteristic. (Which pretty much means they must be finite)
Sort:Axis -> [Axis] -> Float -> Float
Takes an axis to sort along. It also takes a list of axis to take lexical priority over.
Sort foo [] is the standard sorting. Sort foo [bar] means to slice the array up into lists of length 6. Consult the first item in the list, if thats a tie, consult the second item.
All axes used here (oh and the type) must implement a sortable characteristic. (Axis are sortable if their underlying type is) For example an ennumeration axis Axis({Red, Green, Blue}) wouldn’t be sortable, but a date axis would.
I am not sure if you should be able to call sort on an axis, and implicitly sort all data along that axis eg
Axis student=Axis([20])
Int age= get_ages()
String name=get_names()
student.sort(age)
And have the students names get automatically sorted by age.
Combining axis.
Int a=1
Axis foo=Axis([5])
Axis bar=Axis([5])
\\ do stuff
assert_combine(foo,bar)
The first 2 lines create a 5 by 5 array out of a. (and any other variables in use)
The assert_combine(foo,bar)
step will assert that these axis have the same underlying types, and combine them, deleting any elements off the diagonal. This makes a and b alieses of the same axis.
If you are using a rust like ownership model.foo.assert_combine(bar)
will gain ownership of and use up bar.
Functions like matrix inverse take in a tuple of axis and assert that they are the same.
If you are using floats to index your axis, you can’t handle every float. But using lazy evaluation, you can still evaluate at a point, or numerically integrate over a line.
Complicated Axis
The complex numbers behave kind of like an axis (Just add an Axis([2])
and sum works fine, real parts at index 0, imag parts at index 1) , except that the rules for projecting a real numbers into complex is different. And multiplication is different. The Haskellish thing to do, is to let programmers define their own projection functions and own operations. Insist on rules like where is a programmer defined function that turns a number lacking this axis into one with this axis. And is a programmer defined function for things with the axis. (ie and complex multiplication. Don’t attempt to enforce these constraints programmatically. If someone attempts to multiply complex numbers without having defined the complex multiplication, raise a compile time error.) Also throw an error if anyone tries to make a complex bool, string or date. (Unless the programmer wrote a function that worked with dates.)
Maybe you also want axis representing all sorts of odd things. Like polynomials, which can be added and multiplied pointwise (like the float axis), but can also be added elementwise.
Any of this sort of stuff gives up on the idea of all axis types being compatible with all data types.
Variable Axis
Consider this code
Axis foo, Int b=from_list([5,6,8])
\\creates an axis of type Axis([3]), and an int b which is 5,6,8 along that axis.
Axis bar=Axis([b])
Int c=1
This creates a new axis with width 5,6,8. The resulting c resembles the python [[1]*5,[1]*6,[1]*8]
. It consists of a total of 19 ones. Of course its still stored internally as a single 1, because of that compiler optimization for arrays that repeat themselves along an axis.
Note that now assert_combine has to compare lots of numbers to see if they are all equal. (In the worst case. If the user uses b twice to make axis, then that can be seen just by seeing the pointers are the same.) This isn’t a note about performance, the overhead of this should still be small compared with dealing with that many numbers.
Changing b after bar is created shouldn’t make c bigger. b could be immutable, or consumed in the creation of bar.
Note that the size of each axis can only depend on previously defined axis, making this a DAG structure that, in the worst case resembles nested lists.
(If you don’t like this, you can introduce special values that are actually constant to use as array sizes)
Can you give an example of a problem that is difficult to solve with a current language but is easier to solve with an Axis-Oriented language? Feel free to assume that you have a compiler that optimizes things perfectly.
Perhaps my problem is that I’m not close enough to the space (I’ve never worked with an array with 10 dimensions), but I’m having trouble seeing what the concept actually is here. It seems really interesting though, and I’d love to learn more!
As it is now, this post seems like it would fit in better on hacker new, rather than lesswrong. I don’t see how it addresses questions of developing or applying human rationality, broadly interpreted. It could be edited to talk more about how this is applying more general principles of effective thinking, but I don’t really see that here right now. Hence my downvote for the time being.
People can write personal posts on LW that don’t meet Frontpage standards. For example, plenty of rationalists use LW as their personal blog in one way or another and those posts don’t make it to the frontpage but they also end up fitting in here.
Note that this post was frontpaged.
Should I not tick the “moderators may promote to frontpage” by default? I was assuming the moderators to have a clearer idea of what they want for the frontpage than I do.
FYI I was the one who frontpaged this, and didn’t put all that much thought into it. (The “niche topic” consideration is kinda vague, and a bit more ad-hoc-judgment-call-y than other frontpage considerations)
I definitely encourage people to leave ‘moderators may promote to frontpage’ unless they have a personal preference for non-front-pageness, and let it be our problem to navigate the various frontpage judgment calls.
Gordon’s argument implicitly agreed with mtaran that the post wasn’t frontpage material. I think it does meet the requirements in Ruby’s personal vs frontpage post but I’m also sympathetic to the idea that weird programming isn’t really topical for LW.
On the other hand, I don’t use the frontpage and have no skin in this game.