Function composition: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Text replacement - "</source>" to "</syntaxhighlight>")
Line 23: Line 23:
|}
|}


The operator represented by [[Jot]] (<source lang=apl inline>∘</source>, in this context called [[Bind]]) and the 3-train can also be used with constant arrays, then treating the arrays (<source lang=apl inline>A</source>) as constant functions, much as if they were used as operands to the [[Constant]] operator (<source lang=apl inline>A⍨</source>):
The operator represented by [[Jot]] (<source lang=apl inline>∘</syntaxhighlight>, in this context called [[Bind]]) and the 3-train can also be used with constant arrays, then treating the arrays (<source lang=apl inline>A</syntaxhighlight>) as constant functions, much as if they were used as operands to the [[Constant]] operator (<source lang=apl inline>A⍨</syntaxhighlight>):
{| class=wikitable
{| class=wikitable
! Bind !! 3-train
! Bind !! 3-train
Line 33: Line 33:
The above compositions can be summarised as follows:
The above compositions can be summarised as follows:


<source lang=apl inline>  (f⍛g  ) ⍵</source> {{←→}} <source lang=apl inline>(  f ⍵) g      ⍵ </source><br>
<source lang=apl inline>  (f⍛g  ) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>(  f ⍵) g      ⍵ </syntaxhighlight><br>
<source lang=apl inline>⍺ (f⍛g  ) ⍵</source> {{←→}} <source lang=apl inline>(  f ⍺) g      ⍵ </source><br>
<source lang=apl inline>⍺ (f⍛g  ) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>(  f ⍺) g      ⍵ </syntaxhighlight><br>
<source lang=apl inline>  (  g∘h) ⍵</source> {{←→}} <source lang=apl inline>        g (  h ⍵)</source><br>
<source lang=apl inline>  (  g∘h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (  g∘h) ⍵</source> {{←→}} <source lang=apl inline>   ⍺    g (  h ⍵)</source><br>
<source lang=apl inline>⍺ (  g∘h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>   ⍺    g (  h ⍵)</syntaxhighlight><br>


<source lang=apl inline>  (  g⍤h) ⍵</source> {{←→}} <source lang=apl inline>        g (  h ⍵)</source><br>
<source lang=apl inline>  (  g⍤h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (  g⍤h) ⍵</source> {{←→}} <source lang=apl inline>        g (⍺ h ⍵)</source><br>
<source lang=apl inline>⍺ (  g⍤h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (⍺ h ⍵)</syntaxhighlight><br>
<source lang=apl inline>  (  g⍥h) ⍵</source> {{←→}} <source lang=apl inline>        g (  h ⍵)</source><br>
<source lang=apl inline>  (  g⍥h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (  g⍥h) ⍵</source> {{←→}} <source lang=apl inline>(  h ⍺) g (  h ⍵)</source><br>
<source lang=apl inline>⍺ (  g⍥h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>(  h ⍺) g (  h ⍵)</syntaxhighlight><br>


<source lang=apl inline>  (  g h) ⍵</source> {{←→}} <source lang=apl inline>        g (  h ⍵)</source><br>
<source lang=apl inline>  (  g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (  g h) ⍵</source> {{←→}} <source lang=apl inline>        g (⍺ h ⍵)</source><br>
<source lang=apl inline>⍺ (  g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>        g (⍺ h ⍵)</syntaxhighlight><br>
<source lang=apl inline>  (f g h) ⍵</source> {{←→}} <source lang=apl inline>(  f ⍵) g (  h ⍵)</source><br>
<source lang=apl inline>  (f g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>(  f ⍵) g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (f g h) ⍵</source> {{←→}} <source lang=apl inline>(⍺ f ⍵) g (⍺ h ⍵)</source><br>
<source lang=apl inline>⍺ (f g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>(⍺ f ⍵) g (⍺ h ⍵)</syntaxhighlight><br>


<source lang=apl inline>  (A∘g  ) ⍵</source> {{←→}} <source lang=apl inline>   A    g      ⍵ </source><br>
<source lang=apl inline>  (A∘g  ) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>   A    g      ⍵ </syntaxhighlight><br>
<source lang=apl inline>  (  g∘A) ⍵</source> {{←→}} <source lang=apl inline>   ⍵    g      A </source><br>
<source lang=apl inline>  (  g∘A) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>   ⍵    g      A </syntaxhighlight><br>
<source lang=apl inline>  (A g h) ⍵</source> {{←→}} <source lang=apl inline>   A    g (  h ⍵)</source><br>
<source lang=apl inline>  (A g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>   A    g (  h ⍵)</syntaxhighlight><br>
<source lang=apl inline>⍺ (A g h) ⍵</source> {{←→}} <source lang=apl inline>   A    g (⍺ h ⍵)</source><br>
<source lang=apl inline>⍺ (A g h) ⍵</syntaxhighlight> {{←→}} <source lang=apl inline>   A    g (⍺ h ⍵)</syntaxhighlight><br>


== Additional compositions ==
== Additional compositions ==


Additional compositions are possible, even without using an argument more than once or applying a function to its own result. However, most of these are rather trivial shuffled-around versions of the above three. For example, one could define an operator identical to Atop, only that it applies the right operand to the result of the left operand, that is <source lang=apl inline>{⍵⍵ ⍺ ⍺⍺ ⍵}</source>.
Additional compositions are possible, even without using an argument more than once or applying a function to its own result. However, most of these are rather trivial shuffled-around versions of the above three. For example, one could define an operator identical to Atop, only that it applies the right operand to the result of the left operand, that is <source lang=apl inline>{⍵⍵ ⍺ ⍺⍺ ⍵}</syntaxhighlight>.


When Dyalog added Atop and Over, it was with the reasoning that these were the only compositions where the leftmost function acted as the "root" function in the evaluation tree, while the arguments were used each on their respective sides of the constituent functions:
When Dyalog added Atop and Over, it was with the reasoning that these were the only compositions where the leftmost function acted as the "root" function in the evaluation tree, while the arguments were used each on their respective sides of the constituent functions:
Line 61: Line 61:
[[File:AllCompositions.png|427px]]
[[File:AllCompositions.png|427px]]


Of note here is <source lang=apl inline>f⍨∘g⍨</source> which is equivalent to — although with swapped operands — [[Reverse-compose]] <source lang=apl inline>⍛</source> (also called ''Before''), and the mirrored version of Beside <source lang=apl inline>∘</source> (also known as ''Compose'' and ''After''), because it is the only such variation that has been implemented, namely in [[dzaima/APL]] and [[Extended Dyalog APL]].  
Of note here is <source lang=apl inline>f⍨∘g⍨</syntaxhighlight> which is equivalent to — although with swapped operands — [[Reverse-compose]] <source lang=apl inline>⍛</syntaxhighlight> (also called ''Before''), and the mirrored version of Beside <source lang=apl inline>∘</syntaxhighlight> (also known as ''Compose'' and ''After''), because it is the only such variation that has been implemented, namely in [[dzaima/APL]] and [[Extended Dyalog APL]].  


A compositional operator that isn't just a shuffled around version of the basic three, is one that applies one operand between the other operand's dyadic result and the result of that other operand's result when [[swap]]ped: <source lang=apl inline>{(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}</source>. This operator can for example be used to implement [[wikipedia:three-way comparison|three-way comparison]]:
A compositional operator that isn't just a shuffled around version of the basic three, is one that applies one operand between the other operand's dyadic result and the result of that other operand's result when [[swap]]ped: <source lang=apl inline>{(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}</syntaxhighlight>. This operator can for example be used to implement [[wikipedia:three-way comparison|three-way comparison]]:
[https://tio.run/##SyzI0U2pTMzJT///P1jhUdsEhWqNR71bFYAYQu3SBBFApKABIuDiWzVruZJzC8BadIMfdS7hetQ3FcQxUjBWMFEASRn//w8A Try it online!]<source lang=apl>
[https://tio.run/##SyzI0U2pTMzJT///P1jhUdsEhWqNR71bFYAYQu3SBBFApKABIuDiWzVruZJzC8BadIMfdS7hetQ3FcQxUjBWMFEASRn//w8A Try it online!]<source lang=apl>
       S ← {(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}
       S ← {(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}
Line 73: Line 73:
       4 cmp 3
       4 cmp 3
1
1
</source>{{Works in|[[Dyalog APL]], [[NARS2000]], [[ngn/apl]]}}
</syntaxhighlight>{{Works in|[[Dyalog APL]], [[NARS2000]], [[ngn/apl]]}}


== External links ==
== External links ==

Revision as of 21:03, 10 September 2022

Function composition refers to the "gluing" together of two or more functions using a dyadic operator or a train such that the functions are applied to the argument(s) as normal, but in a particular pattern. The term function composition comes from traditional mathematics where it is used for a function when written as . APL generalises this idea to dyadic functions, allowing various patterns of application in addition to the simple application of one monadic function to the result of another monadic function.

Common compositions

Reverse Compose and Beside treat their arguments in an asymmetric way. They can be seen as using a monadic function to pre-process the left or right argument, respectively, before proceeding to apply a main function. Their patterns can be visualised as follows:

Reverse Compose Beside
F⍛g.png F∘g.png

Atop and Over treat their arguments in a symmetric way. They can be seen as using a monadic function to post-process the result or pre-process the argument(s) of a main function. Their patterns can be visualised as follows:

Atop Over
F⍤g.png F⍥g.png

Trains provide a way to apply a function to the result(s) of one (for 2-trains) or two (for 3-trains) other functions. These patterns are also called Atop and Fork, and can be visualised as follows:

2-train 3-train
Fg.png Fgh.png

The operator represented by Jot (<source lang=apl inline>∘</syntaxhighlight>, in this context called Bind) and the 3-train can also be used with constant arrays, then treating the arrays (<source lang=apl inline>A</syntaxhighlight>) as constant functions, much as if they were used as operands to the Constant operator (<source lang=apl inline>A⍨</syntaxhighlight>):

Bind 3-train
A∘g;g∘A.png Agh.png

Summary of rules

The above compositions can be summarised as follows:

<source lang=apl inline>  (f⍛g  ) ⍵</syntaxhighlight> <source lang=apl inline>(  f ⍵) g      ⍵ </syntaxhighlight>
<source lang=apl inline>⍺ (f⍛g  ) ⍵</syntaxhighlight> <source lang=apl inline>(  f ⍺) g      ⍵ </syntaxhighlight>
<source lang=apl inline>  (  g∘h) ⍵</syntaxhighlight> <source lang=apl inline>        g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (  g∘h) ⍵</syntaxhighlight> <source lang=apl inline>   ⍺    g (  h ⍵)</syntaxhighlight>

<source lang=apl inline>  (  g⍤h) ⍵</syntaxhighlight> <source lang=apl inline>        g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (  g⍤h) ⍵</syntaxhighlight> <source lang=apl inline>        g (⍺ h ⍵)</syntaxhighlight>
<source lang=apl inline>  (  g⍥h) ⍵</syntaxhighlight> <source lang=apl inline>        g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (  g⍥h) ⍵</syntaxhighlight> <source lang=apl inline>(  h ⍺) g (  h ⍵)</syntaxhighlight>

<source lang=apl inline>  (  g h) ⍵</syntaxhighlight> <source lang=apl inline>        g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (  g h) ⍵</syntaxhighlight> <source lang=apl inline>        g (⍺ h ⍵)</syntaxhighlight>
<source lang=apl inline>  (f g h) ⍵</syntaxhighlight> <source lang=apl inline>(  f ⍵) g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (f g h) ⍵</syntaxhighlight> <source lang=apl inline>(⍺ f ⍵) g (⍺ h ⍵)</syntaxhighlight>

<source lang=apl inline>  (A∘g  ) ⍵</syntaxhighlight> <source lang=apl inline>   A    g      ⍵ </syntaxhighlight>
<source lang=apl inline>  (  g∘A) ⍵</syntaxhighlight> <source lang=apl inline>   ⍵    g      A </syntaxhighlight>
<source lang=apl inline>  (A g h) ⍵</syntaxhighlight> <source lang=apl inline>   A    g (  h ⍵)</syntaxhighlight>
<source lang=apl inline>⍺ (A g h) ⍵</syntaxhighlight> <source lang=apl inline>   A    g (⍺ h ⍵)</syntaxhighlight>

Additional compositions

Additional compositions are possible, even without using an argument more than once or applying a function to its own result. However, most of these are rather trivial shuffled-around versions of the above three. For example, one could define an operator identical to Atop, only that it applies the right operand to the result of the left operand, that is <source lang=apl inline>{⍵⍵ ⍺ ⍺⍺ ⍵}</syntaxhighlight>.

When Dyalog added Atop and Over, it was with the reasoning that these were the only compositions where the leftmost function acted as the "root" function in the evaluation tree, while the arguments were used each on their respective sides of the constituent functions:

AllCompositions.png

Of note here is <source lang=apl inline>f⍨∘g⍨</syntaxhighlight> which is equivalent to — although with swapped operands — Reverse-compose <source lang=apl inline>⍛</syntaxhighlight> (also called Before), and the mirrored version of Beside <source lang=apl inline>∘</syntaxhighlight> (also known as Compose and After), because it is the only such variation that has been implemented, namely in dzaima/APL and Extended Dyalog APL.

A compositional operator that isn't just a shuffled around version of the basic three, is one that applies one operand between the other operand's dyadic result and the result of that other operand's result when swapped: <source lang=apl inline>{(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}</syntaxhighlight>. This operator can for example be used to implement three-way comparison: Try it online!<source lang=apl>

     S ← {(⍵ ⍵⍵ ⍺) ⍺⍺ (⍺ ⍵⍵ ⍵)}
     cmp ← -S≤
     2 cmp 3

¯1

     3 cmp 3

0

     4 cmp 3

1

</syntaxhighlight>

External links

APL features [edit]
Built-ins Primitives (functions, operators) ∙ Quad name
Array model ShapeRankDepthBoundIndex (Indexing) ∙ AxisRavelRavel orderElementScalarVectorMatrixSimple scalarSimple arrayNested arrayCellMajor cellSubarrayEmpty arrayPrototype
Data types Number (Boolean, Complex number) ∙ Character (String) ∙ BoxNamespaceFunction array
Concepts and paradigms Conformability (Scalar extension, Leading axis agreement) ∙ Scalar function (Pervasion) ∙ Identity elementComplex floorTotal array orderingTacit programming (Function composition, Close composition) ∙ Glyph
Errors LIMIT ERRORRANK ERRORSYNTAX ERRORDOMAIN ERRORLENGTH ERRORINDEX ERRORVALUE ERROR