Split composition: Difference between revisions

Jump to navigation Jump to search
mNo edit summary
No edit summary
Line 1: Line 1:
'''Split-compose''' is a point-free construct, used to pre-process its argument(s) with the left and right-most operand before applying the middle operand between the result. The name was introduced by the [[I|I language]], where it's represented with <code>O</code>, a higher-order function that applies first to the middle function and then the two outer functions (<code>O</code> also represents the [[Over]] operator). It doesn't appear as a primitive in any APL.
'''Split-compose''' is a [[tacit]] construct, used to pre-process its argument(s) with the left and right-most operand before applying the middle operand between the result. Given functions <source lang=apl inline>f</source>, <source lang=apl inline>g</source>, and <source lang=apl inline>h</source>, the split composition on arguments <source lang=apl inline>x</source> and <source lang=apl inline>y</source> is defined as <source lang=apl inline>(f x) g (h y)</source>.


Given functions <source lang=apl inline>F</source>, <source lang=apl inline>G</source>, and <source lang=apl inline>H</source>, the split composition on arguments <source lang=apl inline>x</source> and <source lang=apl inline>y</source> is defined as <source lang=apl inline>(F x) G (H y)</source>.
The name was introduced by the [[I|I language]], where it is represented with <source lang=apl inline>O</source>, a higher-order function that applies first to the middle [[function]] and then the two outer functions (<source lang=apl inline>O</source> also represents the [[Over]] operator). It doesn't appear as a primitive in any APL, nor can it, because it is a [[composition]] of 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-compose and fork can be constructed using two companion operators, tying together the three involved functions.


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.
In [[Extended Dyalog APL]] and [[dzaima/APL]], the construct 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:
<source>
<pre>
    5 ↕⊸×⟜| 5‿¯8‿¯2‿¯5‿3
      5 ⍳⍛×∘| 5 ¯8 ¯2 ¯5 3
0 8 4 15 12 ⟩
5 16 6 20 15
</pre>
This is evaluated as <source lang=apl inline>(⍳5) × (|5 ¯8 ¯2 ¯5 3)</source>. A further example concatenates the reciprocal of the left argument with the negation of the right:
<source lang=apl>
      2(,⍨∘÷⍨∘-⍨⍨)4
0.5 ¯4
</source>
</source>
This is evaluated as <source lang=apl inline>(÷2) × (-4)</source>.
== Alternatives ==


[[Monadic]]ally, the right argument can be [[selfie|duplicated]] and split-compose will be applied asymmetrically, similar to [[hook]]
In dialects that lack Reverse Compose (and even Compose), split-compose can be written 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 expression can be formed with Compose and [[Commute]] (<source lang=apl inline></source>) as <source lang=apl inline>g⍨∘f⍨∘h</source>:
<source>
    +´⊸÷⟜≠ ↕10
⟨ 4.5 ⟩
# This is evaluated as (↕10) +´⊸÷⟜≢ ↕10
</source>
 
In this case, split-compose is precisely equivalent to a [[fork]].
 
<source>
    (+´÷≠) ↕10
4.5
</source>
 
 
 
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>
 
<source lang=apl>
<source lang=apl>
g∘h⍨∘f⍨
      5 ×⍨∘⍳⍨∘| 5 ¯8 ¯2 ¯5 3
 
5 16 6 20 15
g⍨∘f⍨∘h⍨⍨
      2(,⍨∘÷⍨∘-)4
0.5 ¯4
</source>
</source>
 
Note that <source lang=apl inline>g∘h⍨∘f⍨</source> applies <source lang=apl inline>f</source> before <source lang=apl inline>h</source> which can matter for functions with side effects. For example, consider the following where <source lang=apl inline>'x' f⍛g∘h 'y'</source> would print <code>hfg</code>:
For example:
<source lang=apl>
<source lang=apl>
    ÷⍨∘(+/)⍨∘≢⍨⍨ ⍳10
      f←{⍞←⊃⎕SI}
4.5
      g←{⍞←⊃⎕SI}
      h←{⍞←⊃⎕SI}
      'x' g⍨∘f⍨∘h 'y'
hfg
      'x' g∘h⍨∘f⍨ 'y'
fhg
</source>
</source>
 
The equivalent fork is <source lang=apl inline>f⍤⊣ g h⍤⊢</source>, for example:
Whilst these expressions will return the same results (if the functions f, g, and h are pure) the evaluation order is not identical.
 
And (most commonly) as a fork:
 
<source lang=apl>
<source lang=apl>
f⍤⊣ g h⍤⊢
      5 (⍳⍤⊣×|⍤⊢) 5 ¯8 ¯2 ¯5 3
5 16 6 20 15
      2(÷⍤⊣,-⍤⊢)4
0.5 ¯4
</source>
</source>
== See also ==
* [[Tacit programming]]
{{APL syntax}}[[Category:Primitive operators]]
{{APL syntax}}[[Category:Primitive operators]]