Split composition: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
No edit summary
mNo edit summary
 
(14 intermediate revisions by 4 users not shown)
Line 1: Line 1:
'''Split-compose''' is a point-free construct, used to pre-process the argument(s) with the left, and right-most operand before applying the middle operand between the result.
{{Glyphbox|f⍛g∘h}}[[File:Split_composition.png|frameless|right|200px]]
'''Split composition''' is a [[tacit]] pattern, used to pre-process argument(s) with the outer-most operands before applying the middle operand between the result. Given functions <syntaxhighlight lang=apl inline>f</syntaxhighlight>, <syntaxhighlight lang=apl inline>g</syntaxhighlight>, and <syntaxhighlight lang=apl inline>h</syntaxhighlight>, a split composition on arguments <syntaxhighlight lang=apl inline>x</syntaxhighlight> and <syntaxhighlight lang=apl inline>y</syntaxhighlight> is defined as <syntaxhighlight lang=apl inline>(f x) g (h y)</syntaxhighlight>.


It's definition is specified as <source lang=apl inline>(F x) G (H y)</source>.
This construct was introduced by the [[I|I language]] as "split-compose", where it is represented with <syntaxhighlight lang=apl inline>O</syntaxhighlight> which also represents the [[Over]] operator - as it too is a split composition with identical outer operands.  


In BQN, the construct can be formed using [[Before]] <code>(⊸)</code> and [[After]] <code>(⟜)</code>, two [[Function composition|compositional]] [[operator]]s. In this example, we multiply the range of the left argument, with the absolute value of the right.
This doesn't appear as a primitive in any APL, nor can it, because it [[composition|composes]] three functions, while a [[Function composition|compositional operator]] can take no more than two [[operands]]. This situation is identical to that of the [[fork]]. Both split compositions and forks can be constructed using companion operators, tying together the three involved functions.
    5 ↕⊸×⟜| 5‿¯8‿¯2‿¯5‿3
⟨ 0 8 4 15 12 ⟩


[[Monadic]]ally, the right argument can be [[selfie|duplicated]] and split-compose will be applied asymmetrically, similar to [[hook]]
In [[Extended Dyalog APL]] and [[dzaima/APL]], a split composition can be formed using [[Reverse Compose]] (<code>⍛</code>) and [[Compose]] (<code>∘</code>). In this example, we multiply the [[interval]] (integers up until) of the left argument, with the [[Magnitude]] of the right:
    +´⊸÷⟜≠ ↕10
<syntaxhighlight lang=apl>
⟨ 4.5 ⟩
      5 ⍳⍛×∘| 5 ¯8 ¯2 ¯5 3
# This is evaluated as (↕10) +´⊸÷⟜≢ ↕10
5 16 6 20 15
 
</syntaxhighlight>
Monadically, split-compose is precisely equivalent to a [[fork]].
This is evaluated as <syntaxhighlight lang=apl inline>(⍳5) × (|5 ¯8 ¯2 ¯5 3)</syntaxhighlight>. A further example concatenates the reciprocal of the left argument with the negation of the right:
 
<syntaxhighlight lang=apl>
    (+´÷≠) ↕10
       2 ÷⍛,- 4
4.5
0.5 ¯4
 
</syntaxhighlight>
 
This is evaluated as <syntaxhighlight lang=apl inline>(÷2) × (-4)</syntaxhighlight>.
 
== Alternatives ==
In dialects that lack Before, split-compose can be defined differently.
 
In [[Dyalog APL]] you may form the expression with [[Beside]] <code>(∘)</code> and [[Commute]] <code>()</code>
 
g∘h⍨∘f⍨
 
g⍨∘f⍨∘h⍨⍨
 
For example:
       ÷⍨∘(+/)⍨∘≢⍨⍨ ⍳10
4.5
 
Whilst these expressions will return the same results (if the functions f,g, & h are pure) the evaluation order is not identical.
 
And (most commonly) as a fork:
 
f⍤⊣ g h⍤⊢
 
== See also ==
 
* [[Tacit programming]]


In dialects that lack Reverse Compose (and even Compose), split compositions can be denoted either by defining the missing operator(s), or as a single derived function or [[fork]], if this is supported. For example, in [[Dyalog APL]] the pattern can be formed with Compose and [[Commute]] (<syntaxhighlight lang=apl inline>⍨</syntaxhighlight>) as <syntaxhighlight lang=apl inline>g⍨∘f⍨∘h</syntaxhighlight>:
<syntaxhighlight lang=apl>
      5 ×⍨∘⍳⍨∘| 5 ¯8 ¯2 ¯5 3
5 16 6 20 15
      2(,⍨∘÷⍨∘-)4
0.5 ¯4
</syntaxhighlight>
Note that <syntaxhighlight lang=apl inline>g∘h⍨∘f⍨</syntaxhighlight> applies <syntaxhighlight lang=apl inline>f</syntaxhighlight> before <syntaxhighlight lang=apl inline>h</syntaxhighlight> which can matter for functions with side effects. For example, consider the following where <syntaxhighlight lang=apl inline>'x' f⍛g∘h 'y'</syntaxhighlight> would print <code>hfg</code>:
<syntaxhighlight lang=apl>
      f←{⍞←⊃⎕SI}
      g←{⍞←⊃⎕SI}
      h←{⍞←⊃⎕SI}
      'x' g⍨∘f⍨∘h 'y'
hfg
      'x' g∘h⍨∘f⍨ 'y'
fhg
</syntaxhighlight>
The equivalent fork is <syntaxhighlight lang=apl inline>f⍤⊣ g h⍤⊢</syntaxhighlight>, for example:
<syntaxhighlight lang=apl>
      5 (⍳⍤⊣×|⍤⊢) 5 ¯8 ¯2 ¯5 3
5 16 6 20 15
      2(÷⍤⊣,-⍤⊢)4
0.5 ¯4
</syntaxhighlight>
{{APL syntax}}[[Category:Primitive operators]]
{{APL syntax}}[[Category:Primitive operators]]

Latest revision as of 08:45, 23 September 2022

f⍛g∘h
Split composition.png

Split composition is a tacit pattern, used to pre-process argument(s) with the outer-most operands before applying the middle operand between the result. Given functions f, g, and h, a split composition on arguments x and y is defined as (f x) g (h y).

This construct was introduced by the I language as "split-compose", where it is represented with O which also represents the Over operator - as it too is a split composition with identical outer operands.

This doesn't appear as a primitive in any APL, nor can it, because it composes three functions, while a compositional operator can take no more than two operands. This situation is identical to that of the fork. Both split compositions and forks can be constructed using companion operators, tying together the three involved functions.

In Extended Dyalog APL and dzaima/APL, a split composition can be formed using Reverse Compose () and Compose (). In this example, we multiply the interval (integers up until) of the left argument, with the Magnitude of the right:

      5 ⍳⍛×∘| 5 ¯8 ¯2 ¯5 3
5 16 6 20 15

This is evaluated as (⍳5) × (|5 ¯8 ¯2 ¯5 3). A further example concatenates the reciprocal of the left argument with the negation of the right:

      2 ÷⍛,- 4
0.5 ¯4

This is evaluated as (÷2) × (-4).

Alternatives

In dialects that lack Reverse Compose (and even Compose), split compositions can be denoted either by defining the missing operator(s), or as a single derived function or fork, if this is supported. For example, in Dyalog APL the pattern can be formed with Compose and Commute () as g⍨∘f⍨∘h:

      5 ×⍨∘⍳⍨∘| 5 ¯8 ¯2 ¯5 3
5 16 6 20 15
      2(,⍨∘÷⍨∘-)4
0.5 ¯4

Note that g∘h⍨∘f⍨ applies f before h which can matter for functions with side effects. For example, consider the following where 'x' f⍛g∘h 'y' would print hfg:

      f←{⍞←⊃⎕SI}
      g←{⍞←⊃⎕SI}
      h←{⍞←⊃⎕SI}
      'x' g⍨∘f⍨∘h 'y'
hfg
      'x' g∘h⍨∘f⍨ 'y'
fhg

The equivalent fork is f⍤⊣ g h⍤⊢, for example:

      5 (⍳⍤⊣×|⍤⊢) 5 ¯8 ¯2 ¯5 3
5 16 6 20 15
      2(÷⍤⊣,-⍤⊢)4
0.5 ¯4
APL syntax [edit]
General Comparison with traditional mathematicsPrecedenceTacit programming (Train, Hook, Split composition)
Array Numeric literalStringStrand notationObject literalArray notation (design considerations)
Function ArgumentFunction valenceDerived functionDerived operatorNiladic functionMonadic functionDyadic functionAmbivalent functionDefined function (traditional)DfnFunction train
Operator OperandOperator valenceTradopDopDerived operator
Assignment MultipleIndexedSelectiveModified
Other Function axisBracket indexingBranchStatement separatorQuad nameSystem commandUser commandKeywordDot notationFunction-operator overloadingControl structureComment