Simple examples

From APL Wiki
Revision as of 22:08, 10 September 2022 by Adám Brudzewsky (talk | contribs) (Text replacement - "<source" to "<syntaxhighlight")
Jump to navigation Jump to search

This page contains examples that show APL's strengths. The examples require minimal background and have no special dependencies. If these examples are too simple for you, have a look at our advanced examples.

Arithmetic mean

Here is an APL program to calculate the average (arithmetic mean) of a list of numbers, written as a dfn: <syntaxhighlight lang=apl>

     {(+⌿⍵)÷≢⍵} 

</source> It is unnamed: the enclosing braces mark it as a function definition. It can be assigned a name for use later, or used anonymously in a more complex expression.

The <syntaxhighlight lang=apl inline>⍵</source> refers to the argument of the function, a list (or 1-dimensional array) of numbers. The <syntaxhighlight lang=apl inline>≢</source> denotes the tally function, which returns here the length of (number of elements in) the argument <syntaxhighlight lang=apl inline>⍵</source>. The divide symbol <syntaxhighlight lang=apl inline>÷</source> has its usual meaning.

The parenthesised <syntaxhighlight lang=apl inline>+⌿⍵</source> denotes the sum of all the elements of <syntaxhighlight lang=apl inline>⍵</source>. The <syntaxhighlight lang=apl inline>⌿</source> operator combines with the <syntaxhighlight lang=apl inline>+</source> function: the <syntaxhighlight lang=apl inline>⌿</source> fixes the <syntaxhighlight lang=apl inline>+</source> function between each element of <syntaxhighlight lang=apl inline>⍵</source>, so that <syntaxhighlight lang=apl>

     +⌿ 1 2 3 4 5 6

21 </source> is the same as <syntaxhighlight lang=apl>

     1+2+3+4+5+6

21 </source>

Operators

Operators like <syntaxhighlight lang=apl inline>⌿</source> can be used to derive new functions not only from primitive functions like <syntaxhighlight lang=apl inline>+</source>, but also from defined functions. For example <syntaxhighlight lang=apl>

     {⍺,', ',⍵}⌿

</source> will transform a list of strings representing words into a comma-separated list: <syntaxhighlight lang=apl>

     {⍺,', ',⍵}⌿'cow' 'sheep' 'cat' 'dog'

┌────────────────────┐ │cow, sheep, cat, dog│ └────────────────────┘ </source> So back to our mean example. <syntaxhighlight lang=apl inline>(+⌿⍵)</source> gives the sum of the list, which is then divided by <syntaxhighlight lang=apl inline>≢⍵</source>, the number elements in it. <syntaxhighlight lang=apl>

     {(+⌿⍵)÷≢⍵} 3 4.5 7 21

8.875 </source>

Tacit programming

Main article: Tacit programming

In APL’s tacit definition, no braces are needed to mark the definition of a function: primitive functions just combine in a way that enables us to omit any reference to the function arguments — hence tacit. Here is the same calculation written tacitly: <syntaxhighlight lang=apl>

     (+⌿÷≢) 3 4.5 7 21

8.875 </source>

This is a so called 3-train, also known as a fork. It is evaluated like this:

<syntaxhighlight lang=apl>(+⌿ ÷ ≢) 3 4.5 7 21</source>   <syntaxhighlight lang=apl>(+⌿ 3 4.5 7 21) ÷ (≢ 3 4.5 7 21)</source>

Note that <syntaxhighlight lang=apl inline>+⌿</source> is evaluated as a single derived function. The general scheme for monadic 3-trains is the following:

<syntaxhighlight lang=apl>(f g h) ⍵</source>   <syntaxhighlight lang=apl>(f ⍵) g (h ⍵)</source>

But other types of trains are also possible.

Text processing

APL represents text as character lists (vectors), making many text operations trivial.

Split text by delimiter

<syntaxhighlight lang=apl inline>≠</source> gives 1 for true and 0 for false. It pairs up a single element argument with all the elements of the other arguments: <syntaxhighlight lang=apl>

     ','≠'comma,delimited,text'

1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 </source> <syntaxhighlight lang=apl inline>⊢</source> returns its right argument: <syntaxhighlight lang=apl>

         ','⊢'comma,delimited,text'

comma,delimited,text </source> <syntaxhighlight lang=apl inline>⊆</source> returns a list of runs as indicated by runs of 1s, leaving out elements indicated by 0s: <syntaxhighlight lang=apl>

     1 1 0 1 1 1⊆'Hello!'

┌──┬───┐ │He│lo!│ └──┴───┘ </source> We use the comparison vector to partition the right argument:

Try it now! <syntaxhighlight lang=apl>

     ','(≠⊆⊢)'comma,delimited,text'

┌─────┬─────────┬────┐ │comma│delimited│text│ └─────┴─────────┴────┘ </source>

Works in: Dyalog APL

Notice that you can read the tacit function <syntaxhighlight lang=apl inline>≠⊆⊢</source> like an English sentence: The inequality partitions the right argument.

Many dialects do not support the above tacit syntax, and use the glyph <syntaxhighlight lang=apl inline>⊂</source> for partition primitive function. In such dialects, the following formulation can be used: <syntaxhighlight lang=apl>

     (','≠s)⊂s←'comma,delimited,text'

</source>

Works in: APL2, APLX, GNU APL

This assigns the text to the variable <syntaxhighlight lang=apl inline>s</source>, then separately computes the partitioning vector and applies it.

Indices of multiple elements

<syntaxhighlight lang=apl inline>∊</source> gives us a mask for elements (characters) in the left argument that are members of the right argument: <syntaxhighlight lang=apl>

     'mississippi'∊'sp'

0 0 1 1 0 1 1 0 1 1 0 </source> <syntaxhighlight lang=apl inline>⍸</source> gives us the indices where true (1): <syntaxhighlight lang=apl>

     ⍸'mississippi'∊'sp'

3 4 6 7 9 10 </source> We can combine this into an anonymous infix (dyadic) function: <syntaxhighlight lang=apl>

     'mississippi' (⍸∊) 'sp'

3 4 6 7 9 10 </source>

Frequency of characters in a string

The Outer Product allows for an intuitive way to compute the occurrence of characters at a given location in a string: <syntaxhighlight lang=apl>

     'abcd' ∘.= 'cabbage'
0 1 0 0 1 0 0
0 0 1 1 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 0 0

</source> Then it is simply a matter of performing a sum-reduce <syntaxhighlight lang=apl inline>+/</source> to calculate the total frequency of each character:[1] <syntaxhighlight lang=apl>

     +/ 'abcd' ∘.= 'cabbage'
2 2 1 0

</source>

Parenthesis nesting level

"Ken was showing some slides — and one of his slides had something on it that I was later to learn was an APL one-liner. And he tossed this off as an example of the expressiveness of the APL notation. I believe the one-liner was one of the standard ones for indicating the nesting level of the parentheses in an algebraic expression. But the one-liner was very short — ten characters, something like that — and having been involved with programming things like that for a long time and realizing that it took a reasonable amount of code to do, I looked at it and said, “My God, there must be something in this language.”"

Alan Perlis. Almost Perfect Artifacts Improve only in Small Ways: APL is more French than English at APL78.

What was the one-liner for the nesting level of parentheses? It would take a bit of work to figure out, because at the time of the meeting Perlis described, no APL implementation existed. Two possibilities are explained here.

Method A

For this more complex computation, we can expand on the previous example's use of <syntaxhighlight lang=apl inline>∘.=</source>. First we compare all characters to the opening and closing characters; <syntaxhighlight lang=apl>

     '()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'

0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 </source> An opening increases the current level, while a closing decreases, so we convert this to changes (or deltas) by subtracting the bottom row from the top row: <syntaxhighlight lang=apl>

     -⌿'()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'

0 0 0 0 1 0 0 0 0 0 0 1 0 ¯1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 ¯1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 ¯1 ¯1 ¯1 </source> The running sum is what we're looking for: <syntaxhighlight lang=apl>

     +\-⌿'()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'

0 0 0 0 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 3 2 1 </source>

Works in: all APLs

Method B

Alternatively, we can utilise that if the Index Of function <syntaxhighlight lang=apl inline>⍳</source> doesn't find what it is looking for, it returns the next index after the last element in the the lookup array: <syntaxhighlight lang=apl>

      'ABBA'⍳'ABC'

1 2 5

     '()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))'

3 3 3 3 1 3 3 3 3 3 3 1 3 2 3 3 3 3 3 1 3 3 3 3 3 3 1 3 2 3 3 3 3 3 3 1 3 3 3 3 3 3 1 3 3 3 2 2 2 </source> Whenever we have a 1 the parenthesis level increases, and when we have a 2 it decreases. If we have a 3, it remains as-is. We can do this mapping by indexing into these values: <syntaxhighlight lang=apl>

     1 ¯1 0['()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))']

0 0 0 0 1 0 0 0 0 0 0 1 0 ¯1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 ¯1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 ¯1 ¯1 ¯1 </source> The running sum is what we're looking for: <syntaxhighlight lang=apl>

     +\1 ¯1 0['()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))']

0 0 0 0 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 3 2 1 </source>

Works in: all APLs

Grille cypher

A grille is a 500 year old method for encrypting messages.

Represent both the grid of letters and the grille as character matrices. <syntaxhighlight lang=apl> ⎕←(grid grille)←5 5∘⍴¨'VRYIALCLQIFKNEVPLARKMPLFF' '⌺⌺⌺ ⌺ ⌺⌺⌺ ⌺ ⌺ ⌺⌺⌺ ⌺⌺⌺ ⌺⌺' ┌─────┬─────┐ │VRYIA│⌺⌺⌺ ⌺│ │LCLQI│ ⌺⌺⌺ │ │FKNEV│⌺ ⌺ ⌺│ │PLARK│⌺⌺ ⌺⌺│ │MPLFF│⌺ ⌺⌺│ └─────┴─────┘ </source>

Retrieve elements of the grid where there are spaces in the grille. <syntaxhighlight lang=apl>

     grid[⍸grille=' ']

ILIKEAPL </source> An alternative method using ravel. <syntaxhighlight lang=apl>

     (' '=,grille)/,grid

ILIKEAPL </source>

References

  1. Marshall Lochbaum used this example as part of his talk on Outer Product at LambdaConf 2019.
APL development [edit]
Interface SessionTyping glyphs (on Linux) ∙ FontsText editors
Publications IntroductionsLearning resourcesSimple examplesAdvanced examplesMnemonicsISO 8485:1989ISO/IEC 13751:2001A Dictionary of APLCase studiesDocumentation suitesBooksPapersVideosAPL Quote QuadVector journalTerminology (Chinese, German) ∙ Neural networksError trapping with Dyalog APL (in forms)
Sharing code Backwards compatibilityAPLcartAPLTreeAPL-CationDfns workspaceTatinCider
Implementation ResourcesOpen-sourceMagic functionPerformanceAPL hardware
Developers Timeline of corporationsAPL2000DyalogIBMIPSASTSC