5ab5traction5 - World Wide and Wonderful

Masks for array access in APL, and other sundries

As predicted, the APL Orchard did quickly provide alternative syntax for some of my expressions from Wedding Thanksgiving-Versary.

Array access without

The first suggested change came from Adam and it involves changing:

Years ← yr[⍸ {⍵>1977} yr]

into:

Years ← yr/⍨yr>1977 ⍝ Equivalent to (yr>1977)/yr

This was a well-deserved reminder that replicate (/) is more ambiguous than many APL symbols -- it can be either a function or an operator.

I had completely forgotten about this behavioral variation of /!

Essentially what happens is that we pass a series of 0s and 1s to the replicate function. The number of elements of this series must be the same as the number of elements in the structure we are accessing. 0 means "leave the corresponding element out of the result". 1 means "include one copy of the corresponding element in the result".

When used in this way, the term compress is generally used. If we were to provide an integer greater than 1, the corresponding element would appear that many times in the result. (There is also behavior for negative integers that varies across APL implementations.)

Some background on operators vs functions in APL

Though / is often used as a monadic operator in APL, it also exists as a dyadic function as well.

The distinction between operator and function in APL comes from it's origins as both a very early programming language (thus, before operator became a synonym for "built in function represented by a symbol") and as a mathematical notation (they are operators in the Heaviside sense of the word).

That is to say, an APL operator does nothing on it's own but is rather combined with a function in order to provide a modified version of that function. (J, an APL descendant, moved to calling operators adverbs and functions verbs, a distinction that may help to clarify).

A quick example of replicate in operator form:

+/ 3 4 5   ⍝ 12

This could be read aloud as "replicate the addition function across elements of the vector 3, 4, 5".

Reverse it

The in the expression yr/⍨yr>1977 is useful in that it removes the need for parentheses in the expression. It also allows for an arguably more familiar "array access" syntax where the structure being accessed is on the left of the expression determining what pieces to access.

Using to avoid parentheses is a common idiom that nevertheless continues to trip me up. I'm therefore quite thankful to have this simple example to reflect upon.

Dyalog dates are a bit magical

Another suggestion by the ever-helpful Adam was that I could avoid additional computation by using the Dyalog date format directly, rather than converting it into the human-readable day of the week form.

AnnDates/⍨5=7|1⎕DT AnnDates

Here we again see the same pattern with replicate and reverse. Looks like we will have to integrate this into our recognition capacities sooner rather than later!

The associated expression 5=7|1⎕DT AnnDates uses residue (dyadic |) to get the remainder of division by 7. When that equals 5, we are looking at a Thursday!

Easy ranges with dfns.to

Though only included in a footnote, I mentioned that the range 1978..2050 could be constructed via dfns.iotag.

It turns out that dfns.to is a better fit for building a simple range like the one I require.

That said, I will once again be sticking to the vanilla approach in the updated program.

Prettier output with

Lastly, the output can be improved by using mix (monadic ). Compared to my previously used , which outputs a 1-column matrix of 4-element vectors, outputs a 4-column matrix.

The revised program

Utilizing the above changes, the improved program now looks like:

⎕IO ← 0    ⍝ index origin of 0 means that the nth anniversary in our output table reads as expected
yr ← ⍳2050 ⋄ Years ← yr/⍨yr>1977
AnnDates ← Years ∘., ⊂11 26     ⍝ or Years,¨⊂11 26
AnnOnThursday ← 5=7|1⎕DT AnnDates
ThanksAnnDates ← AnnOnThursday/AnnDates
↑ ThanksAnnDates ,¨ ⍸AnnOnThursday

with the output:

1982 11 26  4
1993 11 26 15
1999 11 26 21
2004 11 26 26
2010 11 26 32
2021 11 26 43
2027 11 26 49
2032 11 26 54
2038 11 26 60
2049 11 26 71

Only one call to each (¨), and it's only in our display code! Thanks again Adam and the whole APL Orchard crew.

Update: That final each is removable by using a synonym! The expression:

↑ ThanksAnnDates ,¨ ⍸AnnOnThursday

is equivalent to:

(↑ThanksAnnDates),⍸AnnOnThursday