Train: Difference between revisions

Jump to navigation Jump to search
3,597 bytes added ,  10:58, 11 September 2022
m
Text replacement - "</source>" to "</syntaxhighlight>"
(Separate from tacit programming page)
Tag: Removed redirect
m (Text replacement - "</source>" to "</syntaxhighlight>")
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
A '''train''' is a compound function made up of a series of functions. It's written as an isolated expression (surrounded by parentheses or named) ending in a function. Defined by [[Ken Iverson]] and [[Eugene McDonnell]] in 1988 and added to [[Dyalog APL]] in 2014, trains are considered important for [[tacit programming]] and a characteristic of modern APL.
A '''function train''' is a compound function made up of a series of functions. It's written as an isolated expression (surrounded by parentheses or named) ending in a function. Defined by [[Ken Iverson]] and [[Eugene McDonnell]] in 1988 and added to [[Dyalog APL]] in 2014, trains are considered important for [[tacit programming]] and a characteristic of modern APL.


== Definition ==
== Definition ==


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:
Below, <syntaxhighlight lang=apl inline>⍺</syntaxhighlight> and <syntaxhighlight lang=apl inline>⍵</syntaxhighlight> refer to the arguments of the train. <syntaxhighlight lang=apl inline>f</syntaxhighlight>, <syntaxhighlight lang=apl inline>g</syntaxhighlight>, and <syntaxhighlight lang=apl inline>h</syntaxhighlight> are functions (which themselves can be tacit or not), and <syntaxhighlight lang=apl inline>A</syntaxhighlight> is an array. The arguments are processed by the following rules:


=== 3-trains ===
=== 3-trains ===
A 3-train is a ''fork'', so denoted because its structure resembles a three-tines fork, or a three-pronged pitchfork. The two outer functions are applied first, and their results are used as arguments to the middle function:
A 3-train is a ''fork'', so denoted because its structure resembles a three-tines fork, or a three-pronged pitchfork. The two outer functions are applied first, and their results are used as arguments to the middle function:
{|
{|
|<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>
|-
|-
|<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>
|}
|}
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>
|<syntaxhighlight lang=apl>  (A g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>A g (  h ⍵)</syntaxhighlight>
|-
|-
|<source lang=apl>⍺ (A g h) ⍵</source>|| {{←→}} ||<source lang=apl>A g (⍺ h ⍵)</source>
|<syntaxhighlight lang=apl>⍺ (A g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>A g (⍺ h ⍵)</syntaxhighlight>
|}
|}


Line 22: Line 22:
Most dialects define a 2-train is an ''atop'', equivalent to the function derived using the [[Atop (operator)|Atop]] operator. The left function is applied [[monadic function|monadically]] on the result of the right function:
Most dialects define a 2-train is an ''atop'', equivalent to the function derived using the [[Atop (operator)|Atop]] operator. The left function is applied [[monadic function|monadically]] on the result of the right function:
{|
{|
|<source lang=apl>  (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g (  h ⍵)</source>
|<syntaxhighlight lang=apl>  (g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>g (  h ⍵)</syntaxhighlight>
|-
|-
|<source lang=apl>⍺ (g h) ⍵</source>|| {{←→}} ||<source lang=apl>g (⍺ h ⍵)</source>
|<syntaxhighlight lang=apl>⍺ (g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>g (⍺ h ⍵)</syntaxhighlight>
|}
|}


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]].
Only [[dzaima/APL]] allows <syntaxhighlight lang=apl inline>(A h)</syntaxhighlight>, which it treats as <syntaxhighlight lang=apl inline>A∘h</syntaxhighlight>.<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]].


[[J]] instead defines the 2-train as a [[hook]], equivalent to the function derived using the [[Withe]] operator. The left function is always applied [[dyadic function|dyadically]], taking as right argument, the result of applying the right function on the right argument. If there is no left argument, the sole argument is used also as left argument:
[[J]] instead defines the 2-train as a [[hook]], equivalent to the function derived using the [[Withe]] operator. The left function is always applied [[dyadic function|dyadically]], taking as right argument, the result of applying the right function on the right argument. If there is no left argument, the sole argument is used also as left argument:
{|
{|
|<source lang=apl>  (g h) ⍵</source>|| {{←→}} ||<source lang=apl>⍵ g (h ⍵)</source>
|<syntaxhighlight lang=apl>  (g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>⍵ g (h ⍵)</syntaxhighlight>
|-
|-
|<source lang=apl>⍺ (g h) ⍵</source>|| {{←→}} ||<source lang=apl>⍺ g (h ⍵)</source>
|<syntaxhighlight lang=apl>⍺ (g h) ⍵</syntaxhighlight>|| {{←→}} ||<syntaxhighlight lang=apl>⍺ g (h ⍵)</syntaxhighlight>
|}
|}


Line 39: Line 39:
Trains that use a [[Function-operator_overloading|hybrid function-operator]] in its [[function]] role can run into the problems with the hybrid being parsed as a monadic [[operator]] instead of as a function. This happens when a function appears to the immediate left of the hybrid, causing this function to be bound as the hybrid's operand — the hybrid taking on an operator role — rather than supplying a left [[argument]] or post-processing the result.
Trains that use a [[Function-operator_overloading|hybrid function-operator]] in its [[function]] role can run into the problems with the hybrid being parsed as a monadic [[operator]] instead of as a function. This happens when a function appears to the immediate left of the hybrid, causing this function to be bound as the hybrid's operand — the hybrid taking on an operator role — rather than supplying a left [[argument]] or post-processing the result.


For example, the attempted [[#3-trains|fork]] <source lang=apl inline>f/h</source> is actually parsed as the [[#2-trains|atop]] <source lang=apl inline>(f/)h</source> and the attempted atop <source lang=apl inline>f/</source> is actually parsed as a [[Windowed Reduce|Windowed Reduction]]. There are multiple [[Function-operator_overloading#Mitigation|ways to mitigate this issue]]. For example, the fork can be enforced using the [[Atop (operator)|Atop operator]] by applying identity to the hybrid's result as <source lang=apl inline>f⊢⍤/h</source> and the atop can be enforced by using the explicit Atop operator instead of a 2-train; <source lang=apl inline>f⍤/</source>.
For example, the attempted [[#3-trains|fork]] <syntaxhighlight lang=apl inline>f/h</syntaxhighlight> is actually parsed as the [[#2-trains|atop]] <syntaxhighlight lang=apl inline>(f/)h</syntaxhighlight> and the attempted atop <syntaxhighlight lang=apl inline>f/</syntaxhighlight> is actually parsed as a [[Windowed Reduce|Windowed Reduction]]. There are multiple [[Function-operator_overloading#Mitigation|ways to mitigate this issue]]. For example, the fork can be enforced using the [[Atop (operator)|Atop operator]] by applying identity to the hybrid's result as <syntaxhighlight lang=apl inline>f⊢⍤/h</syntaxhighlight> and the atop can be enforced by using the explicit Atop operator instead of a 2-train; <syntaxhighlight lang=apl inline>f⍤/</syntaxhighlight>.


No problem presents when left argument is supplied as an array (literal or by name reference) and when the hybrid is the leftmost token. For example, <source lang=apl inline>1 0 1/⌽</source> and <source lang=apl inline>/,⊃</source> are parsed as forks.
No problem presents when left argument is supplied as an array (literal or by name reference) and when the hybrid is the leftmost token. For example, <syntaxhighlight lang=apl inline>1 0 1/⌽</syntaxhighlight> and <syntaxhighlight lang=apl inline>/,⊃</syntaxhighlight> are parsed as forks.
 
== History ==
Function trains were first presented under the name "Phrasal forms" by [[Ken Iverson]] and [[Eugene McDonnell]] in a 1989 paper<ref>[[Ken Iverson]] and [[Eugene McDonnell]]. [http://www.jsoftware.com/papers/fork.htm Phrasal forms] at [[APL89]].</ref> of the same name. They called the 2-function form a "hook" and the 3-function form a "fork" based on the shapes of the function call diagrams. On the return flight from [[APL88]], Iverson found the idea when he woke up from a nap and then developed it together with McDonnell.<ref>[[Roger Hui|Hui, Roger]]. [http://keiapl.org/rhui/remember.htm "Remembering Ken Iverson"]. 2004-11.</ref> The use of syntax for trains followed a long history of attempts to define train-like behavior in terms of operators.<ref>[[Roger Hui]] and [[Morten Kromberg]]. [https://dl.acm.org/doi/abs/10.1145/3386319 ''APL since 1978'']. §3.8 Trains Encore. ACM [[HOPL]] IV. 2020-06.</ref>
 
Trains as defined in Phrasal Forms were included in the first versions of [[J]] in 1990. They were added to [[NARS2000]] by 2009,<ref>NARS2000 Wiki. [http://wiki.nars2000.org/index.php?title=Trains&oldid=438 Trains]. Old revision: 2009-02-18.</ref> and [[ngn/apl]] had partial support in 2013. [[K]] defined a different and simpler kind of function train based on linear evaluation.
 
The train definition used in most APL dialects changes the 2-train from a hook to an [[Atop]] in behavior. This change was made in [[Dyalog APL 14.0]] in 2014, under the direction of [[Roger Hui]], who had argued for it by 2006.<ref>[[Roger Hui]]. [https://code.jsoftware.com/wiki/Essays/Hook_Conjunction%3F Hook Conjunction?] J Wiki. First published 2006-05-24.</ref> It now appears in [[APL\iv]], [[dzaima/APL]], [[April]], and [[BQN]], and also matches the function composition featured in [[I]] in 2012.
 
== External links ==
=== Documentation ===
* [https://help.dyalog.com/latest/Content/Language/Introduction/Trains.htm Dyalog]
* [http://wiki.nars2000.org/index.php?title=Trains NARS2000]
* [https://mlochbaum.github.io/BQN/doc/train.html BQN]
* J: [https://code.jsoftware.com/wiki/Vocabulary/hook Hook], [https://code.jsoftware.com/wiki/Vocabulary/fork Fork]
 
=== Tutorials ===
==== Text ====
* [[APL Cultivation]]: [https://chat.stackexchange.com/rooms/52405/conversation/lesson-23-transcribing-to-and-reading-trains Transcribing to and reading trains]
* gitonthescene: [https://gist.github.com/gitonthescene/666c77ee3ed0ae0a79cf8e057584b7fd Forks: Spoon fed]
* gitonthescene: [https://gist.github.com/gitonthescene/5e9c25ab9edd2f2ce0d5ad38d8a8b2b4 Training day]
 
==== Videos ====
* [[APLtrainer]]: [https://www.youtube.com/watch?v=kt4lMZbn-so How to read trains in Dyalog APL code]
* [[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 ==
<references />
<references />
 
{{APL syntax}}[[Category:Tacit programming]][[Category:Kinds of functions]][[Category:Defining functions]]
{{APL syntax}}[[Category:Kinds of functions]][[Category:Defining functions]]

Navigation menu