Maths versus APL#
Let us explore, on a basic level, the differences and the similarities between traditional mathematical notation and APL.
The basic operations are exactly the same, and if it weren’t for the font, you wouldn’t be able to tell the difference:
3 + 4
Well, I kind of lied: there is one obvious difference.
But that’s a functional difference.
While traditional maths notation (that I will occasionally abbreviate to TMN because I am lazy) is static:
APL code can be evaluated, like we saw above.
I just have to type the expression and then ask for the result with a press of the Enter key:
20 + 22
This is the first thing to note about APL – APL is an executable mathematical notation.
As such, let us execute some more mathematical expressions:
10 - 3
34 × 3
102 ÷ 34
These are just examples of things where APL and mathematics are the same.
But there is more! If we agree that we can represent Boolean values with 0s and 1s (where 0 means “false” and 1 means “true”), then the Boolean operators are the same in APL and TMN:
1 ∧ 0
1 ∨ 0
APL even borrows some of TMN’s notation for some set operations.
For example, we use
to say that \(x\) is in \(S\).
In APL, we use ∊
to check for membership:
3 ∊ 1 2 3 4
3 ∊ 5 6 7 8
(Above, we are listing some integers by writing them next to each other.)
We can also do set union and intersection with the conventional mathematical symbols:
1 2 3 ∪ 3 4 5
1 2 3 ∩ 3 4 5
But there are also many places where TMN and APL do not look the same.
In fact, we just saw an example of that!
While mathematics has to use commas (“,”) to separate members of a set, because juxtaposition generally means multiplication, APL can get rid of that visual noise because multiplication is ever only represented by ×
.
That is, we always have to use ×
for multiplication and we only use ×
for multiplication, unlike TMN where we use juxtaposition, \(\cdot\), or \(\times\) for multiplication.
Similarly, TMN represents division by \(\frac{x}{y}\), \(x/y\), or \(x \div y\), whereas APL sticks to using ÷
.
If you are not convinced about the usefulness of being consistent, then suppose (in TMN) that we have
What is \(\{x y z\}\)?
Is it the set with the elements \(3\), \(4\), and \(5\), or is it the set with the single number \(60\), or is it the set containing the element with name “xyz”, that I haven’t defined yet?
How about \(\{x ~ y ~ z\}\)?
In APL, \(\{x ~ y ~ z\}\) would clearly be the three element set, because no operation was explicitly used:
x ← 3
y ← 4
z ← 5
x y z
By the way, these left-pointing arrows can be read as “x gets 3”, “y gets 4”, “z gets 5”.
This is another difference from TMN, where \(=\) is used for both assignment of variables and equality comparison, sometimes making it unclear whether we are assigning a value to a variable or asserting the two things are the same.
In APL, we reserve =
for equality testing:
x = 2
x = 3
So why is APL so similar and so different from TMN?
Because APL was not designed as a programming language, but rather as an alternative to TMN…
Hence it tries to pick TMN up on the things it does well, and it tries to do better on the other things.
That’s because Ken Iverson, the father of APL, believed that having a suitable notation allowed you to convey your thoughts more easily, more clearly, and also believed that a suitable notation meant you could spend more time solving problems, and less time struggling with how to write your solutions down.
(Ken Iverson was much more of a genius than what I am able to convey in such a simplistic sentence, so don’t let my literary limitations have you think little of APL’s raison d’être.)
But why would such an alternative be needed? Let us explore how messy TMN can actually be.
Oh, and by the way, I – the author – am a huge fan of mathematics. I studied mathematics all my life. But after getting a taste of APL, I can no longer look at the traditional mathematical notation like I used to…
In mathematics, exponentiation is denoted with a superscript:
In other words, the positioning of symbols can denote operations…
Is that really a good idea? Clearly you have never seen my handwriting.
APL opts for keeping everything inline, which means all operations get their operators.
For exponentiation, that is *
:
3*2
While we are in the matter of infix operators, would you be so kind as to tell me what the following expression evaluates to?
First work out the exponentiation; multiplication and division are next in the priority line; and finally all the additions and subtractions, from left to right. PEDMAS, was it?
APL takes care of this with a simple rule: everything evaluates from right to left with the exact same priority:
3*2+6-2×5+3÷6
That is why the result above is so wildly different from whatever result you came up with for the mathematical expression.
Maybe this is easier to grasp by contrasting the TMN expression
with the APL one:
5-5-5
Of course, if you really want to, you can use parenthesis to force execution in any order you prefer:
(5-5)-5
But having one single rule to sort out all precedence issues that we might encounter is much better than having to memorise rules and, better still, it removes the burden of guesswork!
Now, you might be wondering “why the heck does APL evaluate everything from right to left instead of everything from left to right?”, and that is a fair question…
But if you are already at that point then you probably accepted that it makes sense to simplify all the precedence rules!
One point to APL. And one point to you, for embracing this so gracefully.
Moving on, I have a question for you. In TMN, what does
mean?
I was taught that’s equal to
that is,
is the function \(f\) applied \(n\) times, with initial argument \(x\).
How would that look like in APL?
First of all, function application is written out like this: f x
.
No need for the parentheses.
In its quest for simplifying and making things unambiguous, it was decided that functions apply to everything that shows up to its right. This is what is called “long right scope”. A rule like this was introduced so that we can boil down parentheses to a bare minimum.
Function application is f x
, and, therefore, applying f
twice would be just f f x
.
But there is another, shorter, way.
Much like *
is used for the “power” operation on numbers, ⍣
is used for the “power” operation on functions!
Hence, (f⍣2) x
is equivalent to f f x
.
The fact that ⍣
and *
are so similar isn’t a coincidence, but it is also relevant that they aren’t exactly the same thing.
Consider the following mathematical equality:
This is how I have seen that equality written all my life, but, strictly speaking, the ² on the trigonometric functions should mean
so the superscripts there are confusing.
Perhaps move them to the right of \(x\), like so:
That is not too bad, but now it looks like we mean
which is definitely not what we mean here.
Perhaps the safest alternative is to be 100% explicit about what we mean:
Meanwhile, in APL this confusion will never arise because *
is for exponentiation and ⍣
is for repeated function application.
Remember when I talked about function application in TMN, and said that’s \(f(x)\)?
Then, why is it that the factorial function is usually represented by \(n!\) ? I.e., by an exclamation mark that goes after the argument?
APL also has the factorial function, but APL gives its best at being consistent, so if function application is f x
then the factorial function need not be different:
!3
!4
Oh well, these are just some of the interesting things that are a bit broken traditional mathematical notation.
I mean, maths still works, but imagine where we could be if the notation we used was just better.
(By no means am I saying that APL is perfect, but it does have some nice qualities.)
Another thing that I would like to bring to your attention pertains to the fact that a good notation unlocks new knowledge.
Without defining the variables, let us focus on the following TMN expressions:
Would you be so kind as to group related expressions together, please?
I will now present to you the equivalent APL expressions, in order:
⌈/v
+/v
∧/P v
×/v
∨/P v
⌊/v
Can you see how that little slash over there, the /
, shows that all six expressions are actually closely related?
You probably didn’t even know what the ⌈
and ⌊
did, but you can probably see the f/
pattern in all the six APL expressions.
Chances are, you grouped \(\sum\) and \(\prod\) together, then \(\max\) and \(\min\), and \(\forall\) and \(\exists\). You probably didn’t even stop to ponder whether there were other relationships between all these operations.
The fact that the notation represents all of these in visually similar ways helps you reflect on the similarity between all these operations: “maximum”, “sum”, “for all”, “product”, “exists”, and “minimum”.
The truth is, all of these operations are reductions, as we call them in APL: operations that take a binary function and then use it to reduce a “list” of values into a single result.
But the f/
pattern also brings another relationship to the surface, which is between the binary function f
itself and the reduction we built.
For \(\sum\), for example, this is generally an immediate relationship:
even though \(\sum\) has no visual similarity to \(+\).
But not as many people think about \(\exists\) in this way:
Granted, most people would probably be able to connect the dots if asked to, but the fact that the dots are already connected represents a huge head start for your brain, because it has to deal with less layers of abstraction and reasoning.
It is a superpower to be able to recognise patterns, and APL wants that to be as easy as possible.
Practical example#
Let me just give you a practical example of using APL notation to determine prime numbers below a certain threshold n
.
Let us start by setting a small threshold:
n ← 20
The candidates for the prime numbers are all positive integers from 1 up to n
, so let us generate those:
⍳n
Now we want to figure out which of these have divisors other than 1 and themselves.
We can find the remainders when those numbers are divided by a potential divisor:
5|⍳n
Therefore, finding divisors amounts to checking when the remainder is 0
:
0=5|⍳n
However, we want to do this for all possible prime numbers and all possible divisors, so we use the outer product to combine all possible divisors with all possible prime numbers:
(⍳n)∘.|⍳n
Each column contains remainders for a specific potential prime number. For example, the last column contains the remainders of 20.
Now we look for remainders equal to 0:
0=(⍳n)∘.|⍳n
Like we said, prime numbers have exactly two divisors, so we should count the number of divisors for each of the numbers by adding those 1s up (with +⌿
, which should resemble +/
if you are paying attention) and then looking for counts that equal 2:
+⌿0=(⍳n)∘.|⍳n
2=+⌿0=(⍳n)∘.|⍳n
Now that we have identified where the primes are, we can use that information to filter them out with /⍨
:
v ← ⍳n
v/⍨2=+⌿0=v∘.|v
We also factored out the vector v
with all the possible prime numbers so that we didn’t have to recompute ⍳n
all the time.
Learning APL is a very enlightening experience, so I recommend you check this “Get Started” page or drop by The APL Orchard, a chatroom where plenty of nice folks will be more than happy to answer your questions and help you start your adventure.