Tacit programming: Difference between revisions

Jump to navigation Jump to search
2,975 bytes added ,  15:31, 8 August 2022
Move some material to a dedicated page on trains
(the intro of this article used the word "trains" without defining it first; trying to make it clearer)
(Move some material to a dedicated page on trains)
(24 intermediate revisions by 7 users not shown)
Line 1: Line 1:
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 to create complex derived functions without specifying any arguments explicitly.
'''Tacit programming''', also called '''[[wikipedia:Tacit_programming|point-free style]]''', refers to usage of tacit [[function]]s that are defined in terms of implicit [[argument]]s. This is in contrast to the explicit use of arguments in [[dfn]]s (<source inline lang=apl>⍺ ⍵</source>) and [[tradfn]]s (which have named arguments). Some APL dialects allow to combine functions into [[train]]s following a small set of rules. This allows creating complex [[derived function]]s without specifying any arguments explicitly.


Known dialects which implement trains are [[Dyalog APL]], [[dzaima/APL]], [[ngn/apl]] and [[NARS2000]].
Dialects which implement trains include [[Dyalog APL]], [[dzaima/APL]], [[ngn/apl]] and [[NARS2000]].


== Primitives ==
== Primitives ==
Line 34: Line 34:


== Trains ==
== Trains ==
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 [[train]] is a series of functions in isolation. An isolated function is either surrounded by parentheses or named.


A 2-train is an ''atop'':
These rules are used for 3-trains:
{|
|<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>
Line 50: Line 44:
The ''left tine'' of a fork can be an array:
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>
|-
|-
|<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]].
In APL (but not [[J]]), these rules are used for 2-trains:
{|
|<source lang=apl>  (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g ( h )</source>
|-
|<source lang=apl>⍺ (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g (⍺ h ⍵)</source>
|}
 
== 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>
=== Conversion to dfns ===
It can help understanding to convert a tacit function to a dfn. For many tacit functions, it is not immediately clear if the intention of the function is to be used monadically or dyadically, or even both. Such knowledge can be conveyed by comments, but sometimes it is possible to spot patterns that are exclusively monadic or dyadic: A function with a bound argument (for example <source lang=apl inline>+∘1</source>) can indicate a monadic function, and in some contexts, <source lang=apl inline>=</source>, which can only be used dyadically, would indicate a monadic function. The website [https://tacit.help tacit.help] provides automated translation of most tacit functions, into both monadic and dyadic, fully parenthesised dfns.
== Examples ==
== 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.
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.
Line 138: Line 182:
       +.×⍨(⊢1↓⍳17)~∘.×⍨1↓⍳17  ⍝ Fork evalution
       +.×⍨(⊢1↓⍳17)~∘.×⍨1↓⍳17  ⍝ Fork evalution
       +.×⍨(1↓⍳17)~∘.×⍨1↓⍳17  ⍝ ⊢ evaluation
       +.×⍨(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
       +.×⍨2 3 5 7 11 13 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
666                          ⍝ the sum of the squares of the primes up to 17
</source>
</source>
Line 152: Line 196:
666                                                  ⍝ ⍎ executes original Accursed train
666                                                  ⍝ ⍎ executes original Accursed train
</source>
</source>
== See also ==
* [[Function composition]]


== External links ==
== External links ==
=== Tutorials ===
=== Tutorials ===
* Dyalog: [http://help.dyalog.com/16.0/Content/RelNotes14.0/Function%20Trains.htm version 14.0 release notes]
<div style="column-width:30em">
==== In text form ====
* [[Learning APL]]: [https://xpqz.github.io/learnapl/tacit.html Trainspotting]
* [[Documentation_suites#Dyalog_APL|Dyalog documentation]]: [https://help.dyalog.com/16.0/Content/RelNotes14.0/Function%20Trains.htm version 14.0 release notes]
* [[Dfns workspace]]: [https://dfns.dyalog.com/n_tacit.htm Translation of <nowiki>[dfns]</nowiki> into tacit form]
* [[APL Cultivation]]: [https://chat.stackexchange.com/rooms/52405/conversation/lesson-23-transcribing-to-and-reading-trains Transcribing to and reading trains]
* [[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)
* gitonthescene: [https://gist.github.com/gitonthescene/666c77ee3ed0ae0a79cf8e057584b7fd Forks: Spoon fed]
* [[APLtrainer]]: [https://www.youtube.com/watch?v=A2LqqBosvY0 Function trains in APL] (video)
* gitonthescene: [https://gist.github.com/gitonthescene/5e9c25ab9edd2f2ce0d5ad38d8a8b2b4 Training day]
* [[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 ===
==== Videos ====
* [http://help.dyalog.com/16.0/Content/RelNotes14.0/Function%20Trains.htm Announcement]
* [[APLtrainer]]: [https://www.youtube.com/watch?v=kt4lMZbn-so How to read trains in Dyalog APL code]
* [http://help.dyalog.com/latest/Content/Language/Introduction/Trains.htm Dyalog]
* [[APLtrainer]]: [https://www.youtube.com/watch?v=A2LqqBosvY0 Function trains in APL]
* [[Dyalog webinar]]: [https://www.youtube.com/watch?v=Enlh5qwwDuY?t=440 Train Spotting in Dyalog APL]
* [[Dyalog '13]]: [https://www.youtube.com/watch?v=7-93GzDqC08 Train Spotting in Version 14.0]
</div>


== References ==
== References ==

Navigation menu