Simple examples: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
Line 92: Line 92:
</source>
</source>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}
Notice of you can read the [[tacit]] function <source lang=apl inline>≠⊆⊢</source> like an English sentence: ''The inequality partitions the right argument''.
Notice that you can read the [[tacit]] function <source lang=apl inline>≠⊆⊢</source> like an English sentence: ''The inequality partitions the right argument''.
 
=== Indices of multiple elements ===
=== Indices of multiple elements ===
<source lang=apl inline>∊</source> gives us a mask for elements (characters) in the left argument that are members of the right argument:
<source lang=apl inline>∊</source> gives us a mask for elements (characters) in the left argument that are members of the right argument:

Revision as of 05:49, 26 August 2020

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:

      {(+⌿⍵)÷≢⍵}

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 refers to the argument of the function, a list (or 1-dimensional array) of numbers. The denotes the tally function, which returns here the length of (number of elements in) the argument . The divide symbol ÷ has its usual meaning.

The parenthesised +⌿⍵ denotes the sum of all the elements of . The operator combines with the + function: the fixes the + function between each element of , so that

      +⌿ 1 2 3 4 5 6
21

is the same as

      1+2+3+4+5+6
21

Operators

Operators like can be used to derive new functions not only from primitive functions like +, but also from defined functions. For example

      {⍺,', ',⍵}⌿

will transform a list of strings representing words into a comma-separated list:

      {⍺,', ',⍵}⌿'cow' 'sheep' 'cat' 'dog'
┌────────────────────┐
│cow, sheep, cat, dog│
└────────────────────┘

So back to our mean example. (+⌿⍵) gives the sum of the list, which is then divided by ≢⍵, the number elements in it.

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

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:

      (+⌿÷≢) 3 4.5 7 21
8.875

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

(+⌿ ÷ ≢) 3 4.5 7 21
(+⌿ 3 4.5 7 21) ÷ (≢ 3 4.5 7 21)

Note that +⌿ is evaluated as a single derived function. The general scheme for monadic 3-trains is the following:

(f g h) ⍵
(f ⍵) g (h ⍵)

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

gives 1 for true and 0 for false. It pairs up a single element argument with all the elements of the other arguments:

      ','≠'comma,delimited,text'
1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1

returns its right argument:

          ','⊢'comma,delimited,text'
comma,delimited,text

returns a list of runs as indicated by runs of 1s, leaving out elements indicated by 0s:

      1 1 0 1 1 1⊆'Hello!'
┌──┬───┐
│He│lo!│
└──┴───┘

We use the comparison vector to partition the right argument:

Try it now!

      ','(≠⊆⊢)'comma,delimited,text'
┌─────┬─────────┬────┐
│comma│delimited│text│
└─────┴─────────┴────┘
Works in: Dyalog APL

Notice that you can read the tacit function ≠⊆⊢ like an English sentence: The inequality partitions the right argument.

Indices of multiple elements

gives us a mask for elements (characters) in the left argument that are members of the right argument:

      'mississippi'∊'sp'
0 0 1 1 0 1 1 0 1 1 0

gives us the indices where true (1):

      ⍸'mississippi'∊'sp'
3 4 6 7 9 10

We can combine this into an anonymous infix (dyadic) function:

      'mississippi' (⍸∊) 'sp'
3 4 6 7 9 10

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:

      '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

Then it is simply a matter of performing a sum-reduce +/ to calculate the total frequency of each character:[1]

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

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 ∘.=. First we compare all characters to the opening and closing characters;

      '()'∘.='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

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:

      -⌿'()'∘.='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

The running sum is what we're looking for:

      +\-⌿'()'∘.='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
Works in: all APLs

Method B

Alternatively, we can utilise that if the Index Of function doesn't find what it is looking for, it returns the next index after the last element in the the lookup array:

       '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

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:

      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

The running sum is what we're looking for:

      +\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
Works in: all APLs

Grille cypher

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

The application of a grille cypher

Represent both the grid of letters and the grille as character matrices.

      ⎕←(grid grille)←5 5∘⍴¨'VRYIALCLQIFKNEVPLARKMPLFF' '⌺⌺⌺ ⌺ ⌺⌺⌺ ⌺ ⌺ ⌺⌺⌺ ⌺⌺⌺  ⌺⌺'
┌─────┬─────┐
│VRYIA│⌺⌺⌺ ⌺│
│LCLQI│ ⌺⌺⌺ │
│FKNEV│⌺ ⌺ ⌺│
│PLARK│⌺⌺ ⌺⌺│
│MPLFF│⌺  ⌺⌺│
└─────┴─────┘

Retrieve elements of the grid where there are spaces in the grille.

      grid[⍸grille=' ']
ILIKEAPL

An alternative method using ravel.

      (' '=,grille)/,grid
ILIKEAPL

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