4,506
edits
Miraheze>Adám Brudzewsky |
|||
(42 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
This page contains examples that show APL's strengths. The examples require minimal background and have no special dependencies. | 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]]: | |||
<source 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 <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 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 | |||
<source lang=apl> | |||
+⌿ 1 2 3 4 5 6 | |||
21 | |||
</source> | |||
is the same as | |||
<source lang=apl> | |||
1+2+3+4+5+6 | |||
21 | |||
</source> | |||
=== 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 | |||
<source lang=apl> | |||
{⍺,', ',⍵}⌿ | |||
</source> | |||
will transform a list of strings representing words into a comma-separated list: | |||
<source lang=apl> | |||
{⍺,', ',⍵}⌿'cow' 'sheep' 'cat' 'dog' | |||
┌────────────────────┐ | |||
│cow, sheep, cat, dog│ | |||
└────────────────────┘ | |||
</source> | |||
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. | |||
<source lang=apl> | |||
{(+⌿⍵)÷≢⍵} 3 4.5 7 21 | |||
8.875 | |||
</source> | |||
=== Tacit programming === | |||
{{Main|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: | |||
<source 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: | |||
{| | |||
|<source lang=apl>(+⌿ ÷ ≢) 3 4.5 7 21</source>|| {{←→}} ||<source lang=apl>(+⌿ 3 4.5 7 21) ÷ (≢ 3 4.5 7 21)</source> | |||
|} | |||
Note that <source lang=apl inline>+⌿</source> is evaluated as a single derived function. | |||
The general scheme for monadic 3-trains is the following: | |||
{| | |||
|<source lang=apl>(f g h) ⍵</source>|| {{←→}} ||<source lang=apl>(f ⍵) g (h ⍵)</source> | |||
|} | |||
But other types of [[Tacit programming#Trains|trains]] are also possible. | |||
==Text processing== | ==Text processing== | ||
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 === | |||
<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: | |||
<source 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> | |||
<source lang=apl inline>⊢</source> returns its right argument: | |||
<source lang=apl> | |||
','⊢'comma,delimited,text' | |||
comma,delimited,text | |||
</source> | |||
<source lang=apl inline>⊆</source> returns a list of runs as indicated by runs of 1s, leaving out elements indicated by 0s: | |||
<source lang=apl> | |||
1 1 0 1 1 1⊆'Hello!' | |||
┌──┬───┐ | |||
│He│lo!│ | |||
└──┴───┘ | |||
</source> | |||
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!] | |||
<source lang=apl> | |||
','(≠⊆⊢)'comma,delimited,text' | |||
┌─────┬─────────┬────┐ | |||
│comma│delimited│text│ | |||
└─────┴─────────┴────┘ | |||
</source> | |||
{{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''. | |||
=== 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> | ||
'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> | ||
< | <source lang=apl inline>⍸</source> gives us the indices where true (1): | ||
< | <source lang=apl> | ||
⍸'mississippi'∊'sp' | ⍸'mississippi'∊'sp' | ||
3 4 6 7 9 10 | 3 4 6 7 9 10 | ||
</ | </source> | ||
We can combine this into an anonymous infix (dyadic) function: | We can combine this into an anonymous infix (dyadic) function: | ||
< | <source lang=apl> | ||
'mississippi' (⍸∊) 'sp' | 'mississippi' (⍸∊) 'sp' | ||
3 4 6 7 9 10 | 3 4 6 7 9 10 | ||
</ | </source> | ||
{{Works in|[[Dyalog APL]], [[NARS2000]], [[dzaima/APL]]}} | {{Works in|[[Dyalog APL]], [[NARS2000]], [[dzaima/APL]]}} | ||
=== 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: | |||
<source 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 <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> | |||
<source lang=apl> | |||
+/ 'abcd' ∘.= 'cabbage' | |||
2 2 1 0 | |||
</source> | |||
=== 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]].}} | ||
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 <source lang=apl inline>∘.=</source>. First we compare all characters to the opening and closing characters; | |||
<source 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: | |||
<source 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: | |||
<source 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> | ||
{{APL | {{Works in|all APLs}} | ||
==== 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: | |||
<source 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: | |||
<source 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: | |||
<source 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 [[wikipedia:grille (cryptography)|grille]] is a 500 year old method for encrypting messages. | |||
[[File:Grille.png|none|500px|frameless|The application of a grille cypher]] | |||
<p> | |||
Represent both the grid of letters and the grille as character matrices. | |||
<source lang=apl> | |||
⎕←(grid grille)←5 5∘⍴¨'VRYIALCLQIFKNEVPLARKMPLFF' '⌺⌺⌺ ⌺ ⌺⌺⌺ ⌺ ⌺ ⌺⌺⌺ ⌺⌺⌺ ⌺⌺' | |||
┌─────┬─────┐ | |||
│VRYIA│⌺⌺⌺ ⌺│ | |||
│LCLQI│ ⌺⌺⌺ │ | |||
│FKNEV│⌺ ⌺ ⌺│ | |||
│PLARK│⌺⌺ ⌺⌺│ | |||
│MPLFF│⌺ ⌺⌺│ | |||
└─────┴─────┘ | |||
</source> | |||
</p> | |||
Retrieve elements of the grid where there are spaces in the grille. | |||
<source lang=apl> | |||
grid[⍸grille=' '] | |||
ILIKEAPL | |||
</source> | |||
An alternative method using [[ravel]]. | |||
<source lang=apl> | |||
(' '=,grille)/,grid | |||
ILIKEAPL | |||
</source> | |||
===References=== | |||
<references/> | |||
{{APL development}} | |||
[[Category:Examples]] |