Now let's define a tacit function. Tacit functions use a tree (or fork if you want) structure where the left and right parts form the arguments to the middle part (which therefore will be called dyadically).
In other words (f g h) X is the same as (f X) g (h X).
. is a dyadic operator. f.g is generalized inner product (substituting f for + and g for ×), while ∘.× is outer product as ∘ serves as a placeholder (i.e. take no further action). Outer product is the same as a table.
@HyperNeutrino Yeah. ∘ isn't a function, but rather a "space occupier" for .'s left operand, giving a related functionality. It is a slight oddity in APL syntax.
@HyperNeutrino Has historical reasons. We may replace it with a more regular syntax in the future. If it bothers you, you can do table←{⍺ ∘.⍺⍺ ⍵} which causes table to be a regular-syntax monadic operator, so +table is addition table.
@HyperNeutrino ⍺ is the left argument, as in Alpha, the leftmost letter of the Greek alphabet. ⍵ is right arg, as in Omega, the rightmost letter. ⍺⍺ is the left (and in this case the only) operand.
@HyperNeutrino Only for operators. Functions can take any of three forms: tacit, dfn, and tradfn. Operators can be only dop and tradop. But that is a bit much to go into now.
⍨ is a monadic operator, i.e. it takes a single operand (a function) on its left. APL operators are left-associative, so monadic operators are post-fix. (Dyadic operators are infix left-associative.)
f⍨ may also be applied monadically, even though f is dyadic. In that case, the single argument (which must of course be on the right) is used as both left AND right argument. Monadic f⍨ can therefore be called "selfie".
@dzaima monadic ↑
Of course, the inverse ("shaped" to nested) is ↓
The arrows indicate that the rank goes up vs down. Rank is the number of dimensions (or axes if you want). A (nested) vector (list) has only one dimension (axis). A matrix (table) has two.
⊢ is the (right) identity function. It points to the right (its result). (If you apply it dyadically, it yields its right argument unmodified, ignoring its left argument)
@HyperNeutrino Exactly. Superfluous as it may seem, it has some neat uses.
Now we are ready to put all the pieces together to get primes. 1↓⍳ is 2…N and the multiplication table of that has all the composite numbers (non-primes).
@Adám yet, that would require complexity of n squared, while filtering each value by modulo against it's square root range is much less (see math.stackexchange.com/questions/422559/…)
I might be wrong about that, as it depends on implementation details (as well as the compiler used to compile the c source)