Tacit programming: Difference between revisions

Jump to navigation Jump to search
9,807 bytes added ,  08:00, 11 August 2020
No edit summary
(39 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Tacit functions apply to implicit arguments following a small set of rules. This is in contrast to the explicit use of arguments in [[dfns]] (<source inline lang=apl>⍺ ⍵</source>) and [[tradfns]] (which have named arguments). Known dialects which implement trains are Dyalog APL, dzaima/apl, ngn/apl and NARS2000.
Tacit functions apply to implicit arguments. This is in contrast to the explicit use of arguments in [[dfns]] (<source inline lang=apl>⍺ ⍵</source>) and [[tradfns]] (which have named arguments). Some APL dialects allow to combine functions into '''trains''' following a small set of rules. This allows creating complex derived functions without specifying any arguments explicitly.
 
Known dialects which implement trains are [[Dyalog APL]], [[dzaima/APL]], [[ngn/apl]] and [[NARS2000]].


== Primitives ==
== Primitives ==
All primitive functions are tacit. Some APLs allow primitive functions to be named.
All [[primitive functions]] are tacit. Some APLs allow primitive functions to be named.
<source lang=apl>
<source lang=apl>
       plus ← +
       plus ← +
Line 8: Line 10:
       6 times 3 plus 5
       6 times 3 plus 5
48
48
</source>
== Derived functions ==
Functions derived from a monadic operator and an operand, or from a dyadic operator and two operands are tacit functions:
<source lang=apl>
      Sum ← +/
      Sum ⍳10
55
      Dot ← +.×
      3 1 4 dot 2 7 1
17
</source>
== Derived operators ==
A dyadic operator with its right operand forms a tacit monadic operator:
<source lang=apl>
      1(+⍣2)10
12
      Twice ← ⍣2
      1 +Twice 10
12
</source>
</source>


== Trains ==
== Trains ==
A train is a series of functions in isolation. An isolated function is either surrounded by parentheses or named. Arguments are processed by the following rules:
A train is a series of functions in isolation. An isolated function is either surrounded by parentheses or named. Below, <source lang=apl inline>⍺</source> and <source lang=apl inline>⍵</source> refer to the arguments of the train. <source lang=apl inline>f</source>, <source lang=apl inline>g</source>, and <source lang=apl inline>h</source> are functions (which themselves can be tacit or not), and <source lang=apl inline>A</source> is an array. The arguments are processed by the following rules:


A 2-train is an ''atop'':
A 2-train is an ''atop'':
{|
|<source lang=apl>  (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g (  h ⍵)</source>
|-
|<source lang=apl>⍺ (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g (⍺ h ⍵)</source>
|}
A 3-train is a ''fork'':
{|
|<source lang=apl>  (f g h) ⍵</source>|| {{←→}} ||<source lang=apl>(  f ⍵) g (  h ⍵)</source>
|-
|<source lang=apl>⍺ (f g h) ⍵</source>|| {{←→}} ||<source lang=apl>(⍺ f ⍵) g (⍺ h ⍵)</source>
|}
The ''left tine'' of a fork can be an array:
{|
|<source lang=apl>  (A g h)</source>|| {{←→}} ||<source lang=apl>A g (  h ⍵)</source>
|-
|<source lang=apl>⍺ (A g h) ⍵</source>|| {{←→}} ||<source lang=apl>A g (⍺ h ⍵)</source>
|}
Only [[dzaima/APL]] allows <source lang=apl inline>(A h)</source>, which it treats as <source lang=apl inline>A∘h</source>.<ref>dzaima/APL: [https://github.com/dzaima/APL/blob/ceea05e25687988ed0980a4abf4b9249b736543f/docs/differences.txt#L19 Differences from Dyalog APL]. Retrieved 09 Jan 2020.</ref> See [[Bind]].
== Debugging ==
In [[Dyalog APL]], analysis of trains is assisted by a [[user command]] <source lang=apl inline>]Boxing on</source>. This is achieved by executing the command <source lang=apl inline>]Boxing on</source> and then entering a train without any parameters. A structure of the train will be displayed.
For example, the "accursed train" from the section below can be analysed like this:
<source lang=apl>
      ]Boxing on
Was OFF
      ((+.×⍨⊢~∘.×⍨)1↓⍳)    ⍝ the train to be analysed
┌───────────────────────────────┬───────┐
│┌───────────┬─────────────────┐│┌─┬─┬─┐│
││┌───────┬─┐│┌─┬─┬───────────┐│││1│↓│⍳││
│││┌─┬─┬─┐│⍨│││⊢│~│┌───────┬─┐│││└─┴─┴─┘│
││││+│.│×││ │││ │ ││┌─┬─┬─┐│⍨││││      │
│││└─┴─┴─┘│ │││ │ │││∘│.│×││ ││││      │
││└───────┴─┘││ │ ││└─┴─┴─┘│ ││││      │
││          ││ │ │└───────┴─┘│││      │
││          │└─┴─┴───────────┘││      │
│└───────────┴─────────────────┘│      │
└───────────────────────────────┴───────┘
</source>
Alternatively, a train can be represented in form of a tree:
<source lang=apl>
      ]Boxing on -trains=tree
Was ON -trains=box
      ((+.×⍨⊢~∘.×⍨)1↓⍳)    ⍝ the train to be analysed
    ┌───┴───┐ 
  ┌─┴─┐  ┌─┼─┐
  ⍨ ┌─┼─┐ 1 ↓ ⍳
┌─┘ ⊢ ~ ⍨     
.    ┌─┘     
┌┴┐    .       
+ ×  ┌┴┐     
      ∘ ×     
</source>
Or fully parenthesised:
<source lang=apl>
      ]Boxing on -trains=parens
Was OFF -trains=box
      ((+.×⍨⊢~∘.×⍨)1↓⍳)    ⍝ the train to be analysed
(((+.×)⍨)(⊢~((∘.×)⍨)))(1↓⍳)
</source>
== Examples ==
One of the major benefits of tacit programming is the ability to convey a short, well-defined idea as an isolated expression. This aids both human readability ([[semantic density]]) and the computer's ability to interpret code, potentially executing special code for particular [[idiom]]s.
=== Plus and minus ===
<source lang=apl>
      (+,-) 2    ⍝ ±2
2 ¯2
      5 (+,-) 2  ⍝ 5±2
7 3
</source>
=== Arithmetic mean ===
<source lang=apl>
      (+⌿÷≢) ⍳10      ⍝ Mean of the first ten integers
5.5
      (+⌿÷≢) 5 4⍴⍳4    ⍝ Mean of columns in a matrix
1 2 3 4
</source>
=== Fractions ===
We can convert decimal numbers to fractions. For example, we can convert <math>2.625</math> to the improper fraction <math>\tfrac{21}{8}</math> with
<source lang=apl>
      (1∧⊢,÷)2.625
21 8
</source>
Alternatively, we can convert it to the mixed fraction <math>2\tfrac{5}{8}</math> with a mixed fraction:
<source lang=apl>
      (1∧0 1∘⊤,÷)2.625
2 5 8
</source>
=== Is it a palindrome? ===
<source lang=apl>
      (⌽≡⊢)'racecar'
1
      (⌽≡⊢)'racecat'
0
</source>
=== Split delimited text ===
<source lang=apl>
      ','(≠⊆⊢)'comma,delimited,text'
┌─────┬─────────┬────┐
│comma│delimited│text│
└─────┴─────────┴────┘
      ' '(≠⊆⊢)'space delimited text'
┌─────┬─────────┬────┐
│space│delimited│text│
└─────┴─────────┴────┘
</source>
=== Component of a vector in the direction of another vector ===
Sometimes a train can make an expression nicely resemble its equivalent definition in traditional mathematical notation. As an example, here is a program to compute the component of a vector <math>\textbf{a}</math> in the direction of another vector <math>\textbf{b}</math>:
:::<math>\textbf{a}_\textbf{b} = (\textbf{a}\cdot\hat{\textbf{b}})\hat{\textbf{b}}</math>
<source lang=apl>
<source lang=apl>
  (g h) ⍵ ⬄ g (  h ⍵)
      Root ← *∘÷⍨              ⍝ Nth root
(g h) ⍵ ⬄ g (h )
      Norm ← 2 Root +.×⍨      ⍝ Magnitude (norm) of numeric vector in Euclidean space
      Unit ← ⊢÷Norm            ⍝ Unit vector in direction of vector
      InDirOf ← (⊢×+.×)∘Unit  ⍝ Component of vector in direction of vector
      3 5 2 InDirOf 0 0 1      ⍝ Trivial example
0 0 2
</source>
</source>
For a more parallel comparison of the notations, see the [[Comparison_with_traditional_mathematics#Practical_example|comparison with traditional mathematics]].


A 3-train is a ''fork'':
===The Number of the Beast===
The following expression for computing the [[wikipedia:666 (number)|number of the Beast]] (and of [[I.P. Sharp]]'s APL-based email system, [[666 BOX]]) nicely illustrates how to read a train.
<source lang=apl>
      ((+.×⍨⊢~∘.×⍨)1↓⍳)17 ⍝ Accursed train
666
</source>
First, <source lang=apl inline>((+.×⍨⊢~∘.×)1↓⍳)</source> is supplied with only one argument <source lang=apl inline>17</source> and is thus interpreted monadically.
 
Second, <source lang=apl inline>(+.×⍨⊢~∘.×⍨)1↓⍳</source> is a 4-train: reading right-to-left, the last 3 components are interpreted as the fork <source lang=apl inline>1↓⍳</source> and the 4-train is interpreted as the atop <source lang=apl inline>(+.×⍨⊢~∘.×⍨)(1↓⍳)</source>.
Similarly, <source lang=apl inline>(+.×⍨⊢~∘.×⍨)</source> is also a 4-train and interpreted as the atop <source lang=apl inline>+.×⍨(⊢~∘.×⍨)</source>.
 
Thus the accursed train is interpreted as <source lang=apl inline>((+.×⍨(⊢~∘.×⍨))(1↓⍳))17</source>. Having read the train, we now evaluate it monadically.
<source lang=apl>
<source lang=apl>
  (f g h) ⍵ ⬄ ( f ⍵) g (  h ⍵)
      ((+.×⍨(⊢~∘.×⍨))(1↓⍳))17 ⍝ Accursed train as an atop over a fork atop a fork
(f g h) ⍵ ⬄ (⍺ f ⍵) g (⍺ h ⍵)
      +.×⍨(⊢~∘.×⍨)1↓⍳17      ⍝ Atop evalution
      +.×⍨(⊢1↓⍳17)~∘.×⍨1↓⍳17  ⍝ Fork evalution
      +.×⍨(1↓⍳17)~∘.×⍨1↓⍳17  ⍝ ⊢ evaluation
      +.×⍨2 3 5 7 11 13 15 17 ⍝ numbers 2 through 17 without those appearing in their multiplication table are primes
666                          ⍝ the sum of the squares of the primes up to 17
</source>
</source>
Note that <source lang=apl inline>((⊢⍨∘.×⍨)1↓⍳)</source> is a train computing primes up to the given input.


The ''left tine'' of a fork (but not an atop) can be an array:
A more satisfying variation of the accursed train is the following.
<source lang=apl>
<source lang=apl>
  (A g h) ⍵ ⬄ A g ( h ⍵)
      (⍎⊢,⍕∘≢)'((+.×⍨⊢~∘.×⍨)1↓⍳)'                    ⍝ Accursed train 2.0
(A g h) ⍵ ⬄ A g (⍺ h ⍵)
      ⍎(⊢,⍕∘≢)'((+.×⍨⊢~∘.×⍨)1↓⍳)'                    ⍝ 4-train intepreted as an atop
      ⍎(⊢'((+.×⍨⊢~∘.×⍨)1↓⍳)'),⍕∘≢'((+.×⍨⊢~∘.×⍨)1↓⍳)' ⍝ fork evaluation
      ⍎'((+.×⍨⊢~∘.×⍨)1↓⍳)','17'                      ⍝ ⊢ evaluation and ⍕∘≢ evaluation
      ⍎'((+.×⍨⊢~∘.×⍨)1↓⍳)17'                        ⍝ , evaluation
666                                                  ⍝ ⍎ executes original Accursed train
</source>
</source>


== Expressing algorithms ==
== External links ==
One of the major benefits of tacit programming is the ability to convey a short, well-defined idea as an isolated expression ([https://aplwiki.com/wiki/Simple_examples#Tacit_programming example]).  
=== Tutorials ===
* Dyalog: [https://help.dyalog.com/16.0/Content/RelNotes14.0/Function%20Trains.htm version 14.0 release notes]
* [[APL Cultivation]]: [https://chat.stackexchange.com/rooms/52405/conversation/lesson-23-transcribing-to-and-reading-trains Transcribing to and reading trains]
* [[APLtrainer]]: [https://www.youtube.com/watch?v=kt4lMZbn-so How to read trains in Dyalog APL code] (video)
* [[APLtrainer]]: [https://www.youtube.com/watch?v=A2LqqBosvY0 Function trains in APL] (video)
* [[Dyalog webinar]]: [https://www.youtube.com/watch?v=Enlh5qwwDuY?t=440 Train Spotting in Dyalog APL] (video)
* [[Dyalog '13]]: [https://www.youtube.com/watch?v=7-93GzDqC08 Train Spotting in Version 14.0] (video)
 
=== Documentation ===
* [https://help.dyalog.com/16.0/Content/RelNotes14.0/Function%20Trains.htm Announcement]
* [https://help.dyalog.com/latest/Content/Language/Introduction/Trains.htm Dyalog]
 
== References ==
<references/>


{{APL Language}}
{{APL syntax}}[[Category:Tacit programming| ]]
trusted
69

edits

Navigation menu