Leading axis theory: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Text replacement - "<source" to "<syntaxhighlight")
m (Text replacement - "</source>" to "</syntaxhighlight>")
 
Line 5: Line 5:
The leading axis theory as a complete model of programming is best exemplified by [[J]], since it was designed entirely using the theory from the start. While various APLs have developed or adopted features of the leading axis model, [[backwards compatibility]] requirements can prevent them from making certain changes to align with the theory.
The leading axis theory as a complete model of programming is best exemplified by [[J]], since it was designed entirely using the theory from the start. While various APLs have developed or adopted features of the leading axis model, [[backwards compatibility]] requirements can prevent them from making certain changes to align with the theory.


J defines all one-dimensional functions to work on the first [[axis]], that is, to manipulate [[major cell]]s of their arguments. In this way it unifies APL's pairs of first- and last-axis functions and operators including [[Reverse]], [[Rotate]], [[Replicate]], [[Expand]], [[Reduce]], and [[Scan]]. J retains two functions corresponding to <syntaxhighlight lang=apl inline>,</source> and <syntaxhighlight lang=apl inline>⍪</source>, with <syntaxhighlight lang=j inline>,</source> as [[Ravel]] and [[Catenate First]] and <syntaxhighlight lang=j inline>,.</source> for second- (rather than last-) axis forms of these functions; <syntaxhighlight lang=j inline>,.</source> is identical to <syntaxhighlight lang=j inline>,"_1</source> (which transliterates to APL <syntaxhighlight lang=apl inline>,⍤¯1</source>) in both valences.
J defines all one-dimensional functions to work on the first [[axis]], that is, to manipulate [[major cell]]s of their arguments. In this way it unifies APL's pairs of first- and last-axis functions and operators including [[Reverse]], [[Rotate]], [[Replicate]], [[Expand]], [[Reduce]], and [[Scan]]. J retains two functions corresponding to <syntaxhighlight lang=apl inline>,</syntaxhighlight> and <syntaxhighlight lang=apl inline>⍪</syntaxhighlight>, with <syntaxhighlight lang=j inline>,</syntaxhighlight> as [[Ravel]] and [[Catenate First]] and <syntaxhighlight lang=j inline>,.</syntaxhighlight> for second- (rather than last-) axis forms of these functions; <syntaxhighlight lang=j inline>,.</syntaxhighlight> is identical to <syntaxhighlight lang=j inline>,"_1</syntaxhighlight> (which transliterates to APL <syntaxhighlight lang=apl inline>,⍤¯1</syntaxhighlight>) in both valences.


J also extends [[Rotate]] so that it can work on multiple leading axes rather than a single axis: additional values in the left argument apply to leading axes of the right in order. This aligns Rotate with the [[SHARP APL]] extensions to [[Take]], [[Drop]], and [[Squad]] allowing short left arguments: in each case the left argument is a [[vector]] corresponding to axes of the right argument starting at the first.
J also extends [[Rotate]] so that it can work on multiple leading axes rather than a single axis: additional values in the left argument apply to leading axes of the right in order. This aligns Rotate with the [[SHARP APL]] extensions to [[Take]], [[Drop]], and [[Squad]] allowing short left arguments: in each case the left argument is a [[vector]] corresponding to axes of the right argument starting at the first.
Line 20: Line 20:
! Compatibility              !! Functions
! Compatibility              !! Functions
|-
|-
| Already compatible        || [[Grade]] (<syntaxhighlight lang=apl inline>⍋</source>, <syntaxhighlight lang=apl inline>⍒</source>), [[Decode]] (<syntaxhighlight lang=apl inline>⊥</source>), [[Encode]] (<syntaxhighlight lang=apl inline>⊤</source>)
| Already compatible        || [[Grade]] (<syntaxhighlight lang=apl inline>⍋</syntaxhighlight>, <syntaxhighlight lang=apl inline>⍒</syntaxhighlight>), [[Decode]] (<syntaxhighlight lang=apl inline>⊥</syntaxhighlight>), [[Encode]] (<syntaxhighlight lang=apl inline>⊤</syntaxhighlight>)
|-
|-
| Use first axis form only  || [[Reverse]], [[Rotate]] (<syntaxhighlight lang=apl inline>⊖</source>), [[Replicate]], [[Reduce]] (<syntaxhighlight lang=apl inline>⌿</source>), [[Expand]], [[Scan]] (<syntaxhighlight lang=apl inline>⍀</source>), [[Catenate]] (<syntaxhighlight lang=apl inline>⍪</source>)
| Use first axis form only  || [[Reverse]], [[Rotate]] (<syntaxhighlight lang=apl inline>⊖</syntaxhighlight>), [[Replicate]], [[Reduce]] (<syntaxhighlight lang=apl inline>⌿</syntaxhighlight>), [[Expand]], [[Scan]] (<syntaxhighlight lang=apl inline>⍀</syntaxhighlight>), [[Catenate]] (<syntaxhighlight lang=apl inline>⍪</syntaxhighlight>)
|-
|-
| Extendible to leading axes || [[Take]] (<syntaxhighlight lang=apl inline>↑</source>), [[Drop]] (<syntaxhighlight lang=apl inline>↓</source>), [[Squad Indexing]] (<syntaxhighlight lang=apl inline>⌷</source>), [[scalar dyadic]]s, [[Unique]] (<syntaxhighlight lang=apl inline>∪</source> or <syntaxhighlight lang=apl inline>↑</source>) and most [[set function]]s (<syntaxhighlight lang=apl inline>⍳∪∩~</source>)
| Extendible to leading axes || [[Take]] (<syntaxhighlight lang=apl inline>↑</syntaxhighlight>), [[Drop]] (<syntaxhighlight lang=apl inline>↓</syntaxhighlight>), [[Squad Indexing]] (<syntaxhighlight lang=apl inline>⌷</syntaxhighlight>), [[scalar dyadic]]s, [[Unique]] (<syntaxhighlight lang=apl inline>∪</syntaxhighlight> or <syntaxhighlight lang=apl inline>↑</syntaxhighlight>) and most [[set function]]s (<syntaxhighlight lang=apl inline>⍳∪∩~</syntaxhighlight>)
|-
|-
| Incompatible              || [[Split]] (<syntaxhighlight lang=apl inline>↓</source>), [[First]] (<syntaxhighlight lang=apl inline>↑</source> or <syntaxhighlight lang=apl inline>⊃</source>), [[Membership]] (<syntaxhighlight lang=apl inline>∊</source>), [[Partition]] (<syntaxhighlight lang=apl inline>⊂</source> and <syntaxhighlight lang=apl inline>⊆</source>)
| Incompatible              || [[Split]] (<syntaxhighlight lang=apl inline>↓</syntaxhighlight>), [[First]] (<syntaxhighlight lang=apl inline>↑</syntaxhighlight> or <syntaxhighlight lang=apl inline>⊃</syntaxhighlight>), [[Membership]] (<syntaxhighlight lang=apl inline>∊</syntaxhighlight>), [[Partition]] (<syntaxhighlight lang=apl inline>⊂</syntaxhighlight> and <syntaxhighlight lang=apl inline>⊆</syntaxhighlight>)
|-
|-
| Unclear                    || [[Find]] (<syntaxhighlight lang=apl inline>⍷</source>)
| Unclear                    || [[Find]] (<syntaxhighlight lang=apl inline>⍷</syntaxhighlight>)
|-
|-
| Designed for leading axes  || [[Rank operator]] (<syntaxhighlight lang=apl inline>⍤</source>), [[Tally]] (<syntaxhighlight lang=apl inline>≢</source>), [[Interval Index]] (<syntaxhighlight lang=apl inline>⍸</source>), [[Key]] (<syntaxhighlight lang=apl inline>⌸</source>), [[Raze]] (<syntaxhighlight lang=apl inline>⊃</source>)
| Designed for leading axes  || [[Rank operator]] (<syntaxhighlight lang=apl inline>⍤</syntaxhighlight>), [[Tally]] (<syntaxhighlight lang=apl inline>≢</syntaxhighlight>), [[Interval Index]] (<syntaxhighlight lang=apl inline>⍸</syntaxhighlight>), [[Key]] (<syntaxhighlight lang=apl inline>⌸</syntaxhighlight>), [[Raze]] (<syntaxhighlight lang=apl inline>⊃</syntaxhighlight>)
|}
|}


Line 55: Line 55:
|}
|}


[[Index Of]] in SHARP APL was not extended to apply to left argument [[major cell]]s as in J and Dyalog; instead it was given rank <syntaxhighlight lang=apl inline>1 0</source> making such a change impossible. In A+ not only [[Index Of]] but also [[Membership]] was changed to follow the leading axis model, breaking compatibility with other APLs. A+ also restricts [[Take]] and [[Drop]] to allow only a [[singleton]] left argument (but any right argument rank is permitted).
[[Index Of]] in SHARP APL was not extended to apply to left argument [[major cell]]s as in J and Dyalog; instead it was given rank <syntaxhighlight lang=apl inline>1 0</syntaxhighlight> making such a change impossible. In A+ not only [[Index Of]] but also [[Membership]] was changed to follow the leading axis model, breaking compatibility with other APLs. A+ also restricts [[Take]] and [[Drop]] to allow only a [[singleton]] left argument (but any right argument rank is permitted).


== History ==
== History ==

Latest revision as of 21:46, 10 September 2022

Leading axis theory, or the leading axis model, is an approach to array language design and use that emphasizes working with arrays by manipulating their cells and mapping functions over leading axes implicitly using function rank or explicitly using the Rank operator. It was initially developed in SHARP APL in the early 1980s and is now a major feature of J and Dyalog APL, as well as languages influenced by these. The name "leading axis" comes from the frame, which consists of leading axes of an array, the related concept of leading axis agreement, which extends scalar conformability, and the emphasis on first axis forms of functions while deprecating or discarding other choices of axis.

Features

The leading axis theory as a complete model of programming is best exemplified by J, since it was designed entirely using the theory from the start. While various APLs have developed or adopted features of the leading axis model, backwards compatibility requirements can prevent them from making certain changes to align with the theory.

J defines all one-dimensional functions to work on the first axis, that is, to manipulate major cells of their arguments. In this way it unifies APL's pairs of first- and last-axis functions and operators including Reverse, Rotate, Replicate, Expand, Reduce, and Scan. J retains two functions corresponding to , and , with , as Ravel and Catenate First and ,. for second- (rather than last-) axis forms of these functions; ,. is identical to ,"_1 (which transliterates to APL ,⍤¯1) in both valences.

J also extends Rotate so that it can work on multiple leading axes rather than a single axis: additional values in the left argument apply to leading axes of the right in order. This aligns Rotate with the SHARP APL extensions to Take, Drop, and Squad allowing short left arguments: in each case the left argument is a vector corresponding to axes of the right argument starting at the first.

The Rank operator is present in every language influenced by leading axis theory. By mapping over leading axes of the arguments, it allows a left operand which works with leading axes of its own arguments to be applied on axes other than the first. The Rank operator is the reason to define functions on the leading axes: by applying Rank to a leading-axis function, the function can be made to work on any axis or contiguous sequence of axes in the argument.

In J and SHARP APL, every function has a rank defined by the language. For example, scalar functions inherently have rank 0 as they apply only to scalars. J and SHARP APL also define close compositions, which compose two functions while retaining the rank of the first one applied. While the concept of applying with rank makes these features possible, it's unclear whether they are part of leading axis theory or simply a decision made by two languages with a shared heritage. J introduced non-close compositions, and Dyalog APL has added only non-close compositions, avoiding introducing function rank or close compositions despite otherwise adhering to leading axis theory.

Adoption in APL

Because APL was designed before the leading axis model was developed, many APL primitives do not naturally adhere to the theory and some are not compatible with it at all. The following table describes how functions and operators that act on specific axes of their arguments (omitting for example Enclose and Match which apply to entire arrays) interact with leading axis theory.

Compatibility Functions
Already compatible Grade (, ), Decode (), Encode ()
Use first axis form only Reverse, Rotate (), Replicate, Reduce (), Expand, Scan (), Catenate ()
Extendible to leading axes Take (), Drop (), Squad Indexing (), scalar dyadics, Unique ( or ) and most set functions (⍳∪∩~)
Incompatible Split (), First ( or ), Membership (), Partition ( and )
Unclear Find ()
Designed for leading axes Rank operator (), Tally (), Interval Index (), Key (), Raze ()

In addition to these, the Rank operator and scalar dyadics can be extended with leading axis agreement, so that arguments with different-length frames can match as long as one frame is a prefix of the other. The original introduction of Rank had only an analogue of scalar extension, where an argument with an empty frame is repeated to pair it with an argument with a non-empty frame. The following extensions have been made in order to support leading axis theory:

Functions SHARP APL Dyalog APL A+ J BQN
Take, Drop 19.0 13.0 Yes Yes Yes
Indexing function 19.0 13.0 Yes Yes Yes
Bracket indexing No No Yes N/A N/A
Scalar dyadics No No No Yes Yes
Index Of Incompatible 14.0 Yes Yes Yes
Membership Incompatible Incompatible Yes Yes Yes
Unique Yes 17.0 N/A Yes Yes
Union, Intersection, Without No No N/A Yes N/A

Index Of in SHARP APL was not extended to apply to left argument major cells as in J and Dyalog; instead it was given rank 1 0 making such a change impossible. In A+ not only Index Of but also Membership was changed to follow the leading axis model, breaking compatibility with other APLs. A+ also restricts Take and Drop to allow only a singleton left argument (but any right argument rank is permitted).

History

Leading axis theory was first developed by employees of I. P. Sharp Associates including Ken Iverson, Arthur Whitney, and Bob Bernecky in the early 1980s: the Rank operator itself is attributed to Whitney, who invented it while travelling to the APL82 conference.[1] It was further developed by Iverson and Roger Hui when creating the J language in the 1990s and 2000s; the leading axis model and its various incompatibilities with APL had been a major reason to break with APL and create a new language.

Leading axis theory was brought to nested APLs by Dyalog APL in the 2010s after Dyalog Ltd. employed Hui. Working with Jay Foad and Morten Kromberg, Hui designed and implemented versions of Rank and other J functionality compatible with Dyalog's nested arrays.

References


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 floorArray ordering (Total) ∙ Tacit programming (Function composition, Close composition) ∙ GlyphLeading axis theoryMajor cell searchFirst-class function
Errors LIMIT ERRORRANK ERRORSYNTAX ERRORDOMAIN ERRORLENGTH ERRORINDEX ERRORVALUE ERROREVOLUTION ERROR