Simple examples: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Added GNU APL equivalent expression for Split by Delimiter example)
m (→‎Parenthesis nesting level: Link "one-liner")
 
(4 intermediate revisions by 2 users not shown)
Line 4: Line 4:


Here is an APL program to calculate the average (arithmetic mean) of a list of numbers, written as a [[dfn]]:
Here is an APL program to calculate the average (arithmetic mean) of a list of numbers, written as a [[dfn]]:
<source lang=apl>
<syntaxhighlight lang=apl>
       {(+⌿⍵)÷≢⍵}  
       {(+⌿⍵)÷≢⍵}  
</source>
</syntaxhighlight>
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.
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 <source lang=apl inline>⍵</source> refers to the argument of the function, a list (or 1-dimensional array) of numbers. The <source lang=apl inline>≢</source> denotes the [[tally]] function, which returns here the length of (number of elements in) the argument <source lang=apl inline>⍵</source>. The divide symbol <source lang=apl inline>÷</source> has its usual meaning.
The <syntaxhighlight lang=apl inline>⍵</syntaxhighlight> refers to the argument of the function, a list (or 1-dimensional array) of numbers. The <syntaxhighlight lang=apl inline>≢</syntaxhighlight> denotes the [[tally]] function, which returns here the length of (number of elements in) the argument <syntaxhighlight lang=apl inline>⍵</syntaxhighlight>. The divide symbol <syntaxhighlight lang=apl inline>÷</syntaxhighlight> has its usual meaning.


The parenthesised <source lang=apl inline>+⌿⍵</source> denotes the sum of all the elements of <source lang=apl inline>⍵</source>. The <source lang=apl inline>⌿</source> operator combines with the <source lang=apl inline>+</source> function: the <source lang=apl inline>⌿</source> fixes the <source lang=apl inline>+</source> function between each element of <source lang=apl inline>⍵</source>, so that
The parenthesised <syntaxhighlight lang=apl inline>+⌿⍵</syntaxhighlight> denotes the sum of all the elements of <syntaxhighlight lang=apl inline>⍵</syntaxhighlight>. The <syntaxhighlight lang=apl inline>⌿</syntaxhighlight> operator combines with the <syntaxhighlight lang=apl inline>+</syntaxhighlight> function: the <syntaxhighlight lang=apl inline>⌿</syntaxhighlight> fixes the <syntaxhighlight lang=apl inline>+</syntaxhighlight> function between each element of <syntaxhighlight lang=apl inline>⍵</syntaxhighlight>, so that
<source lang=apl>
<syntaxhighlight lang=apl>
       +⌿ 1 2 3 4 5 6
       +⌿ 1 2 3 4 5 6
21
21
</source>
</syntaxhighlight>
is the same as
is the same as
<source lang=apl>
<syntaxhighlight lang=apl>
       1+2+3+4+5+6
       1+2+3+4+5+6
21
21
</source>
</syntaxhighlight>
=== Operators ===
=== Operators ===
[[Operator]]s like <source lang=apl inline>⌿</source> can be used to derive new functions not only from [[primitive function]]s like <source lang=apl inline>+</source>, but also from defined functions. For example
[[Operator]]s like <syntaxhighlight lang=apl inline>⌿</syntaxhighlight> can be used to derive new functions not only from [[primitive function]]s like <syntaxhighlight lang=apl inline>+</syntaxhighlight>, but also from defined functions. For example
<source lang=apl>
<syntaxhighlight lang=apl>
       {⍺,', ',⍵}⌿
       {⍺,', ',⍵}⌿
</source>
</syntaxhighlight>
will transform a list of strings representing words into a comma-separated list:
will transform a list of strings representing words into a comma-separated list:
<source lang=apl>
<syntaxhighlight lang=apl>
       {⍺,', ',⍵}⌿'cow' 'sheep' 'cat' 'dog'
       {⍺,', ',⍵}⌿'cow' 'sheep' 'cat' 'dog'
┌────────────────────┐
┌────────────────────┐
│cow, sheep, cat, dog│
│cow, sheep, cat, dog│
└────────────────────┘
└────────────────────┘
</source>
</syntaxhighlight>
So back to our mean example. <source lang=apl inline>(+⌿⍵)</source> gives the sum of the list, which is then divided by <source lang=apl inline>≢⍵</source>, the number elements in it.
So back to our mean example. <syntaxhighlight lang=apl inline>(+⌿⍵)</syntaxhighlight> gives the sum of the list, which is then divided by <syntaxhighlight lang=apl inline>≢⍵</syntaxhighlight>, the number elements in it.
<source lang=apl>
<syntaxhighlight lang=apl>
       {(+⌿⍵)÷≢⍵} 3 4.5 7 21
       {(+⌿⍵)÷≢⍵} 3 4.5 7 21
8.875
8.875
</source>
</syntaxhighlight>


=== Tacit programming ===
=== Tacit programming ===
Line 44: Line 44:


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:
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:
<source lang=apl>
<syntaxhighlight lang=apl>
       (+⌿÷≢) 3 4.5 7 21
       (+⌿÷≢) 3 4.5 7 21
8.875
8.875
</source>
</syntaxhighlight>


This is a so called 3-train, also known as a ''fork''. It is evaluated like this:
This is a so called 3-train, also known as a ''fork''. It is evaluated like this:
{|
{|
|<source lang=apl>(+⌿ ÷ ≢) 3 4.5 7 21</source>|| {{←→}} ||<source lang=apl>(+⌿ 3 4.5 7 21) ÷ (≢ 3 4.5 7 21)</source>
|<syntaxhighlight lang=apl>(+⌿ ÷ ≢) 3 4.5 7 21</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>(+⌿ 3 4.5 7 21) ÷ (≢ 3 4.5 7 21)</syntaxhighlight>
|}
|}


Note that <source lang=apl inline>+⌿</source> is evaluated as a single derived function.
Note that <syntaxhighlight lang=apl inline>+⌿</syntaxhighlight> is evaluated as a single derived function.
The general scheme for monadic 3-trains is the following:
The general scheme for monadic 3-trains is the following:
{|
{|
|<source lang=apl>(f g h) ⍵</source>|| {{←→}} ||<source lang=apl>(f ⍵) g (h ⍵)</source>
|<syntaxhighlight lang=apl>(f g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>(f ⍵) g (h ⍵)</syntaxhighlight>
|}
|}


Line 65: Line 65:
APL represents text as character lists (vectors), making many text operations trivial.
APL represents text as character lists (vectors), making many text operations trivial.
=== Split text by delimiter ===
=== Split text by delimiter ===
<source lang=apl inline>≠</source> gives 1 for true and 0 for false. It [[scalar function|pairs up]] a single element argument with all the elements of the other arguments:
<syntaxhighlight lang=apl inline>≠</syntaxhighlight> gives 1 for true and 0 for false. It [[scalar function|pairs up]] a single element argument with all the elements of the other arguments:
<source lang=apl>
<syntaxhighlight lang=apl>
       ','≠'comma,delimited,text'
       ','≠'comma,delimited,text'
1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1
1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1
</source>
</syntaxhighlight>
<source lang=apl inline>⊢</source> returns its right argument:
<syntaxhighlight lang=apl inline>⊢</syntaxhighlight> returns its right argument:
<source lang=apl>
<syntaxhighlight lang=apl>
           ','⊢'comma,delimited,text'
           ','⊢'comma,delimited,text'
comma,delimited,text
comma,delimited,text
</source>
</syntaxhighlight>
<source lang=apl inline>⊆</source> returns a list of runs as indicated by runs of 1s, leaving out elements indicated by 0s:
<syntaxhighlight lang=apl inline>⊆</syntaxhighlight> returns a list of runs as indicated by runs of 1s, leaving out elements indicated by 0s:
<source lang=apl>
<syntaxhighlight lang=apl>
       1 1 0 1 1 1⊆'Hello!'
       1 1 0 1 1 1⊆'Hello!'
┌──┬───┐
┌──┬───┐
│He│lo!│
│He│lo!│
└──┴───┘
└──┴───┘
</source>
</syntaxhighlight>
We use the comparison [[vector]] to [[partition]] the right argument:
We use the comparison [[vector]] to [[partition]] the right argument:


[https://tryapl.org/?a=%27%2C%27%28%u2260%u2286%u22A2%29%27comma%2Cdelimited%2Ctext%27&run Try it now!]
[https://tryapl.org/?a=%27%2C%27%28%u2260%u2286%u22A2%29%27comma%2Cdelimited%2Ctext%27&run Try it now!]
<source lang=apl>
<syntaxhighlight lang=apl>
       ','(≠⊆⊢)'comma,delimited,text'
       ','(≠⊆⊢)'comma,delimited,text'
┌─────┬─────────┬────┐
┌─────┬─────────┬────┐
│comma│delimited│text│
│comma│delimited│text│
└─────┴─────────┴────┘
└─────┴─────────┴────┘
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}
Notice that 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 <syntaxhighlight lang=apl inline>≠⊆⊢</syntaxhighlight> like an English sentence: ''The inequality partitions the right argument''.


The above [[tacit]] syntax is not supported by [[GNU APL]]. As a more traditional [https://aplwiki.com/wiki/Migration_level dialect] it uses ⊂ as [[partition]]:
Many dialects do not support the above [[tacit]] syntax, and use the [[glyph]] <syntaxhighlight lang=apl inline>⊂</syntaxhighlight> for partition [[primitive function]]. In such dialects, the following formulation can be used:
[http://juergen-sauermann.de/try-GNU-APL Try it now!]
<syntaxhighlight lang=apl>
<source lang=apl>
       (','≠s)⊂s←'comma,delimited,text'
       (','≠s)⊂s←'comma,delimited,text'
</source>
</syntaxhighlight>
{{Works in|[[GNU APL]]}}
{{Works in|[[APL2]], [[APLX]], [[GNU APL]]}}
This assigns the text to the variable <syntaxhighlight lang=apl inline>s</syntaxhighlight>, then separately computes the partitioning vector and applies it.


=== 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:
<syntaxhighlight lang=apl inline>∊</syntaxhighlight> gives us a mask for elements (characters) in the left argument that are members of the right argument:
<source lang=apl>
<syntaxhighlight lang=apl>
       'mississippi'∊'sp'
       'mississippi'∊'sp'
0 0 1 1 0 1 1 0 1 1 0
0 0 1 1 0 1 1 0 1 1 0
</source>
</syntaxhighlight>
<source lang=apl inline>⍸</source> gives us the indices where true (1):
<syntaxhighlight lang=apl inline>⍸</syntaxhighlight> gives us the indices where true (1):
<source lang=apl>
<syntaxhighlight lang=apl>
       ⍸'mississippi'∊'sp'
       ⍸'mississippi'∊'sp'
3 4 6 7 9 10
3 4 6 7 9 10
</source>
</syntaxhighlight>
We can combine this into an anonymous infix (dyadic) function:
We can combine this into an anonymous infix (dyadic) function:
<source lang=apl>
<syntaxhighlight lang=apl>
       'mississippi' (⍸∊) 'sp'
       'mississippi' (⍸∊) 'sp'
3 4 6 7 9 10
3 4 6 7 9 10
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[NARS2000]], [[dzaima/APL]]}}
{{Works in|[[Dyalog APL]], [[NARS2000]], [[dzaima/APL]]}}


=== Frequency of characters in a string ===
=== 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:
The [[Outer Product]] allows for an intuitive way to compute the occurrence of characters at a given location in a string:
<source lang=apl>
<syntaxhighlight lang=apl>
       'abcd' ∘.= 'cabbage'
       'abcd' ∘.= 'cabbage'
  0 1 0 0 1 0 0
  0 1 0 0 1 0 0
Line 127: Line 127:
  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 0
</source>
</syntaxhighlight>
Then it is simply a matter of performing a sum-reduce <source lang=apl inline>+/</source> to calculate the total frequency of each character:<ref name="Marshall LambaConf 2019">[[Marshall Lochbaum]] used this example as part of his talk on [[Outer Product]] at LambdaConf 2019.</ref>
Then it is simply a matter of performing a sum-reduce <syntaxhighlight lang=apl inline>+/</syntaxhighlight> to calculate the total frequency of each character:<ref name="Marshall LambaConf 2019">[[Marshall Lochbaum]] used this example as part of his talk on [[Outer Product]] at LambdaConf 2019.</ref>
<source lang=apl>
<syntaxhighlight lang=apl>
       +/ 'abcd' ∘.= 'cabbage'
       +/ 'abcd' ∘.= 'cabbage'
  2 2 1 0
  2 2 1 0
</source>
</syntaxhighlight>


=== Parenthesis nesting level ===
=== Parenthesis nesting level ===
{{quote | "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]]. ''[https://www.jsoftware.com/papers/perlis78.htm Almost Perfect Artifacts Improve only in Small Ways: APL is more French than English]'' at [[APL78]].}}
{{quote | "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]]. ''[https://www.jsoftware.com/papers/perlis78.htm 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.
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 ====
==== Method A ====
For this more complex computation, we can expand on the previous example's use of <source lang=apl inline>∘.=</source>. First we compare all characters to the opening and closing characters;
For this more complex computation, we can expand on the previous example's use of <syntaxhighlight lang=apl inline>∘.=</syntaxhighlight>. First we compare all characters to the opening and closing characters;
<source lang=apl>
<syntaxhighlight lang=apl>
       '()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'
       '()'∘.='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 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
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>
</syntaxhighlight>
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:
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:
<source lang=apl>
<syntaxhighlight lang=apl>
       -⌿'()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'
       -⌿'()'∘.='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
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>
</syntaxhighlight>
The running sum is what we're looking for:
The running sum is what we're looking for:
<source lang=apl>
<syntaxhighlight lang=apl>
       +\-⌿'()'∘.='plus(square(a),plus(square(b),times(2,plus(a,b)))'
       +\-⌿'()'∘.='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
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>
</syntaxhighlight>
{{Works in|all APLs}}
{{Works in|all APLs}}
==== Method B ====
==== Method B ====
Alternatively, we can utilise that if the [[Index Of]] function <source 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:
Alternatively, we can utilise that if the [[Index Of]] function <syntaxhighlight lang=apl inline>⍳</syntaxhighlight> doesn't find what it is looking for, it returns the next index after the last element in the the lookup array:
<source lang=apl>
<syntaxhighlight lang=apl>
       'ABBA'⍳'ABC'
       'ABBA'⍳'ABC'
1 2 5
1 2 5
       '()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))'
       '()'⍳'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
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>
</syntaxhighlight>
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:
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:
<source lang=apl>
<syntaxhighlight lang=apl>
       1 ¯1 0['()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))']
       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
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>
</syntaxhighlight>
The running sum is what we're looking for:
The running sum is what we're looking for:
<source lang=apl>
<syntaxhighlight lang=apl>
       +\1 ¯1 0['()'⍳'plus(square(a),plus(square(b),times(2,plus(a,b)))']
       +\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
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>
</syntaxhighlight>
{{Works in|all APLs}}
{{Works in|all APLs}}


Line 180: Line 180:
<p>
<p>
Represent both the grid of letters and the grille as character matrices.
Represent both the grid of letters and the grille as character matrices.
<source lang=apl>
<syntaxhighlight lang=apl>
       ⎕←(grid grille)←5 5∘⍴¨'VRYIALCLQIFKNEVPLARKMPLFF' '⌺⌺⌺ ⌺ ⌺⌺⌺ ⌺ ⌺ ⌺⌺⌺ ⌺⌺⌺  ⌺⌺'
       ⎕←(grid grille)←5 5∘⍴¨'VRYIALCLQIFKNEVPLARKMPLFF' '⌺⌺⌺ ⌺ ⌺⌺⌺ ⌺ ⌺ ⌺⌺⌺ ⌺⌺⌺  ⌺⌺'
┌─────┬─────┐
┌─────┬─────┐
Line 189: Line 189:
│MPLFF│⌺  ⌺⌺│
│MPLFF│⌺  ⌺⌺│
└─────┴─────┘
└─────┴─────┘
</source>
</syntaxhighlight>
</p>
</p>
Retrieve elements of the grid where there are spaces in the grille.
Retrieve elements of the grid where there are spaces in the grille.
<source lang=apl>
<syntaxhighlight lang=apl>
       grid[⍸grille=' ']
       grid[⍸grille=' ']
ILIKEAPL
ILIKEAPL
</source>
</syntaxhighlight>
An alternative method using [[ravel]].
An alternative method using [[ravel]].
<source lang=apl>
<syntaxhighlight lang=apl>
       (' '=,grille)/,grid
       (' '=,grille)/,grid
ILIKEAPL
ILIKEAPL
</source>
</syntaxhighlight>
===References===
===References===
<references/>
<references/>

Latest revision as of 01:32, 10 March 2024

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.

Many dialects do not support the above tacit syntax, and use the glyph for partition primitive function. In such dialects, the following formulation can be used:

      (','≠s)⊂s←'comma,delimited,text'
Works in: APL2, APLX, GNU APL

This assigns the text to the variable s, then separately computes the partitioning vector and applies it.

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