Split composition: Difference between revisions
m (Text replacement - "</source>" to "</syntaxhighlight>") |
m (Text replacement - "<source" to "<syntaxhighlight") |
||
Line 1: | Line 1: | ||
'''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 < | '''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 <syntaxhighlight lang=apl inline>f</syntaxhighlight>, <syntaxhighlight lang=apl inline>g</syntaxhighlight>, and <syntaxhighlight lang=apl inline>h</syntaxhighlight>, the 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>. | ||
The name was introduced by the [[I|I language]], where it is represented with < | The name was introduced by the [[I|I language]], where it is represented with <syntaxhighlight lang=apl inline>O</syntaxhighlight>, a higher-order function that applies first to the middle [[function]] and then the two outer functions (<syntaxhighlight lang=apl inline>O</syntaxhighlight> 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 [[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: | 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: | ||
< | <syntaxhighlight lang=apl> | ||
5 ⍳⍛×∘| 5 ¯8 ¯2 ¯5 3 | 5 ⍳⍛×∘| 5 ¯8 ¯2 ¯5 3 | ||
5 16 6 20 15 | 5 16 6 20 15 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
This is evaluated as < | 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> | ||
2(,⍨∘÷⍨∘-⍨⍨)4 | 2(,⍨∘÷⍨∘-⍨⍨)4 | ||
0.5 ¯4 | 0.5 ¯4 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
This is evaluated as < | This is evaluated as <syntaxhighlight lang=apl inline>(÷2) × (-4)</syntaxhighlight>. | ||
== Alternatives == | == Alternatives == | ||
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]] (< | 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]] (<syntaxhighlight lang=apl inline>⍨</syntaxhighlight>) as <syntaxhighlight lang=apl inline>g⍨∘f⍨∘h</syntaxhighlight>: | ||
< | <syntaxhighlight lang=apl> | ||
5 ×⍨∘⍳⍨∘| 5 ¯8 ¯2 ¯5 3 | 5 ×⍨∘⍳⍨∘| 5 ¯8 ¯2 ¯5 3 | ||
5 16 6 20 15 | 5 16 6 20 15 | ||
Line 23: | Line 23: | ||
0.5 ¯4 | 0.5 ¯4 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Note that < | 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} | f←{⍞←⊃⎕SI} | ||
g←{⍞←⊃⎕SI} | g←{⍞←⊃⎕SI} | ||
Line 33: | Line 33: | ||
fhg | fhg | ||
</syntaxhighlight> | </syntaxhighlight> | ||
The equivalent fork is < | The equivalent fork is <syntaxhighlight lang=apl inline>f⍤⊣ g h⍤⊢</syntaxhighlight>, for example: | ||
< | <syntaxhighlight lang=apl> | ||
5 (⍳⍤⊣×|⍤⊢) 5 ¯8 ¯2 ¯5 3 | 5 (⍳⍤⊣×|⍤⊢) 5 ¯8 ¯2 ¯5 3 | ||
5 16 6 20 15 | 5 16 6 20 15 |
Revision as of 10:40, 11 September 2022
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 f
, g
, and h
, the split composition on arguments x
and y
is defined as (f x) g (h y)
.
The name was introduced by the I language, where it is represented with O
, a higher-order function that applies first to the middle function and then the two outer functions (O
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 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 Extended Dyalog APL and dzaima/APL, the construct 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-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 (⍨
) 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