Comparison of APL dialects
All APL dialects share core features, and at least the primitives are backwards compatible with those of APL.SV. However, there are important dialectal differences, the most significant of which are described in this article.
Flat versus Nested
One of the most significant differences between APLs is the choice of array model, namely nested or flat. Originally, all APLs were entirely flat, that is, the only scalar values supported were simple and had to be either numbers and characters, and an array had to be homogeneous, that is, consisting entirely of a single type. SHARP APL introduced the box as a third type, such that a box could hold any other array (including a box array), and this allowed for arrays contain other arrays. NARS introduced the nested array model, where any arrays can be an actual element of another array. Most currently maintained dialects (Dyalog APL, NARS2000, APL2, GNU APL, and others) use the nested array model.
Disclose
Disclose is defined, on scalars, to be the inverse of Enclose, giving the sole element of that scalar. This behavior is extended to arbitrary arrays in one of two ways: Mix, which combines all elements, and First, which returns only the first (in ravel order).
In the SHARP APL family, Disclose is written >
, and given a function rank of 0, which causes it to behave as Mix. First is not a primitive.
In nested APL dialects, Disclose is written ⊃
, and it was extended to First by NARS and to Mix by APL2. The other possible meaning is given the glyph ↑
and named "Mix" or "First" (not "Disclose") as appropriate. Dialects might choose either assignment of glyphs, and Dyalog APL and APL*PLUS allow either to be chosen based on Migration Level.
Glyph | Meaning | Dialects |
---|---|---|
> |
Mix | SHARP APL, A, A+ |
⊃ |
Mix | APL2, ISO/IEC 13751:2001, APL2C, APLX, NARS2000, GNU APL, Kap |
⊃ |
First | ngn/apl, Co-dfns, dzaima/APL, April |
⊃ |
Configurable | Dyalog APL, APL*PLUS, APL+Win, APL64 |
Function definition
- Main article: Function styles
Dialects offer a variety of ways to create functions and operators. The three major branches are defined functions, which use a header declaring the function and argument names, anonymous functions such as dfns, which also consist of a list of statements but have no header and use fixed argument names, and tacit functions, which are created by manipulating existing functions with no reference to arguments.
Defined functions were the dominant form for most of APL's history, with only some niche forms based on direct definition notation appearing in the 1980s: the direct definition operator in NARS and a library to translate this notation to defined functions in SHARP APL. Function assignment, a necessary feature for tacit programming, began to appear in the 1980s, such as in Dyalog APL version 4.0 in 1986. However, trains, which make larger-scale tacit programming feasible, were not introduced to APL until around 2010. Dyalog's dfns were introduced in 1996 to slow initial adoption; nearly all new dialects of the 2010s and later support a similar syntax. Because of the widespread use of dfns, several of these dialects no longer support a traditional function definition notation.
Numeric types
- Main article: Number
Traditionally, APL supports only one numeric type that is visible to the user, such as a floating-point number, or complex number whose components are floating-point. Other numeric types may be used by the implementation, but only for optimization: for example, APL\360 uses packed 1-bit Boolean and 4-bit integer arrays that are automatically converted to float if an operation yields a value that doesn't fit in the type. ISO/IEC 13751:2001 specifies that different representations of a number must be indistinguishable to a conforming program (which can call primitives but not implementation-specific system functions).
Most often the numeric type is a 64-bit float, for instance HFP in early IBM dialects and IEEE 754 in new dialects since the 1980s. Dyalog APL supports 128-bit decimal floats by setting ⎕FR
. Modern dialects tend to support complex numbers, with exceptions including dzaima/APL, APLX, and APL+Win. Dialects with complex numbers also extend Circular (○
) to left arguments designed for complex numbers.
Some newer dialects provide additional types that are distinguishable from floats, often by greater precision. Extended-precision integers are one possibility: for example, dzaima/APL provides these if requested with a trailing L
in a numeric literal or ⎕BIG
, while Kap uses exact rational numbers by default. NARS2000 supports numerous numeric types, and April provides access to the Common Lisp numeric tower, which also includes many types. GNU APL doesn't support arbitrary precision, but uses 64-bit integers by default, much like J or K.
Conformability
All APLs implement scalar extension in scalar dyadic functions, and Each if present. However, a few dialects differ in their support for singleton extension. Most support it fully, so that a singleton of any rank is extended. APL2 supports it only for scalars and one-element vectors (and ISO/IEC_13751:2001 specifies only this behavior), and dzaima/APL and Kap support scalar extension only.
Furthermore, dialects that implement the Rank operator differ in their conformability rules for frames. Dyalog APL and SHARP APL implement scalar agreement only, NARS2000 implements singleton agreement, and A+ implements leading axis agreement (in addition to extra options allowing the programmer to specify outer-product-like treatment of some axes).
Index origin
A few dialects fix the index origin to 0 rather than allowing it to be configured: A+, APL#, ngn/apl, Co-dfns, and Kap.
Depth
Dyalog APL defines Depth (≡
) to return negative numbers when the depth is uneven. Most other dialects instead define it to return the maximum depth. The original NARS paper assigned the glyph to a function called Simple, which simply answered if the argument was simple or not, without reporting the actual depth. It was thus equivalent to today's 1=≡,Y
.
Language features
The following table shows support for various APL features: nesting either with boxes or the nested array model, defined functions or similar syntax, control structures, dfn-style anonymous functions, tacit programming, particularly with trains, complex numbers, arbitrary-precision integers, Unicode support, and namespaces or a similar encapsulation feature. The precise syntax and capabilities of these features might differ between dialects that support them.
Dialects included in the first row include APL\360, APL\1130, APL*PLUS before II, APL/700, APL.SV, APL 5100, MCM/70, VS APL, APL\3000, and Aplette. Dates for APL+Win include those for APL*PLUS. Extended Dyalog APL and Dyalog APL Vision have the same feature set as Dyalog APL.
Dialect | Nesting | Tradfns | Control | Dfns | Tacit | Complex | Big int | Unicode | Namespace |
---|---|---|---|---|---|---|---|---|---|
APL\360, APL.SV, … | No | Yes | No | No | No | No | No | No | No |
APL+Win | Nested (1989) | Yes | 1994 | No | No | No | No | No | 2006 |
SHARP APL | Boxes (1981) | Yes | No | No | No | 1981 | No | No | No |
NARS | Nested | Yes | No | direct def | No | No | No | No | No |
Dyalog APL | Nested | Yes | 1996 | 1996 | 2014 | 2011 | No | 2008 | 1994 |
APL2 | Nested | Yes | No | No | No | Yes | No | No | 1987 |
A+ | Boxes | Yes | Yes | No | Some | No | No | No | No |
SAX | Boxes | Yes | Yes | No | Some | No | No | No | No |
APL2C | Nested | Yes | Yes | No | No | No | No | No | No |
APLX | Nested | Yes | Yes | No | No | No | No | No | No |
NARS2000 | Nested | Yes | Yes | Yes | 2009 | Yes | Yes | UCS-2 | No |
VisualAPL | Nested | Yes | Yes | No | No | No | No | Yes | Yes |
APL# | Nested | No | Yes | Yes | Yes | No | No | Yes | Yes |
ngn/apl | Nested | No | No | Yes | Yes | Yes | No | Yes | No |
GNU APL | Nested | Yes | If-else | Limited | No | Yes | No | Yes | Yes |
April | Nested | No | No | Yes | Yes | Yes | Yes | Yes | Yes |
dzaima/APL | Nested | No | No | Yes | Yes | No | Yes | Yes | Yes |
APL\iv | Lists | No | No | Yes | Yes | Yes | No | Yes | No |
Kap | Nested | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
APL64 | Nested | Yes | Yes | No | No | No | No | Yes | Yes |
Development and platform
Shown are the release year, year of last release for inactive languages, withdrawal or discontinuation year for products that are no longer available, developer, implementation language, and host system. Systems capable of being compiled for multiple native hosts are indicated as "portable".
Dialect | Released | Inactive | Dropped | Developer | Language | Host |
---|---|---|---|---|---|---|
APL\1130 | 1968 | ? | IBM | 1130 assembler | IBM 1130 | |
APL\360 | 1968 | 1972 | 2012 | IBM | BAL | S/360–z/Architecture, IBM 5100+ |
APL*PLUS | 1970 | 1995 | 2012 | STSC | BAL, C | S/370, TRS-80, portable |
APL/700 | 1971? | ? | Burroughs | ALGOL 60 | Burroughs B 6700/B 7700 | |
APL.SV | 1973 | ? | IBM | BAL | ||
APL 5100 | 1976 | ? | IBM | BAL | IBM 5100 | |
MCM/70 | 1974 | 1983 | MCM | MCM/70 | ||
VS APL | 1976 | ? | IBM | BAL | OS/VS, DOS/VS | |
SHARP APL | 1976 | 1989 | 1993? | IPSA | S/370, later portable | |
APL\3000 | 1976 | 1980s | Hewlett-Packard | HP 3000 Series II / III | ||
NARS | 1981 | 1989? | STSC | 370 assembler, APL | System/370 | |
Dyalog APL | 1983 | Dyalog Ltd. | C, C++, APL | Portable | ||
A+ | 1988 | 2014 | Arthur Whitney | C++ | Portable | |
APL2 | 1984 | IBM | IBM mainframes, portable | |||
SAX | 1993 | 2000 | 2017? | Soliton | C | Portable |
APL+Win | 1995 | 2019 | APL2000 | Portable | ||
APL2C | 2001 | 2002 | Tilman Otto | C | Windows 9x/NT/2000 | |
APLX | 2002 | 2016 | 2016 | MicroAPL Ltd. | C, C++ | Portable |
NARS2000 | 2006 | 2019 | Bob Smith | C, APL | Portable | |
VisualAPL | 2009 | 2011 | APL2000 | C# | .NET (CLI) | |
APL# | 2010 | 2012 | Dyalog Ltd. | C# | .NET (CLI) | |
ngn/apl | 2011 | 2018 | Nick Nickolov | Javascript | In-browser, Node.js | |
GNU APL | 2013 | Jürgen Sauermann | C++ | Portable | ||
Aplette | 2014 | 2020 | Greg F. Johnson | C | Portable | |
Co-dfns | 2014 | Aaron Hsu | Dyalog APL | C, ArrayFire (GPU) targets | ||
April | 2018 | Andrew Sengul | Common Lisp | Common Lisp runtime | ||
dzaima/APL | 2018 | 2020 | dzaima | Java, Processing | JVM, Android | |
APL\iv | 2018 | 2019 | ktye | Go | Portable | |
Extended Dyalog APL | 2018 | 2021 | Adám Brudzewsky | Dyalog APL | Dyalog APL | |
Kap | 2020 | Elias Mårtenson | Kotlin | Portable | ||
APL64 | 2022 | APL2000 | C# | Portable | ||
Dyalog APL Vision | 2022 | Adám Brudzewsky | Dyalog APL | Dyalog APL |
See also
- Unicode#Comparison of implementations
- Take#Extension support
- Replicate#Extension support
- Mix#Language support
- Laminate#Extension support
- Not#Extensions
- Interval Index#History
- Leading axis theory#Adoption in APL
- Array notation#Comparison of array notations
- Timeline of APL primitives
External links
- Omnibar lists all glyphs with their meanings and allows custom comparisons between dialects:
APL dialects [edit] | |
---|---|
Maintained | APL+Win ∙ APL2 ∙ APL64 ∙ APL\iv ∙ Aplette ∙ April ∙ Co-dfns ∙ Dyalog APL ∙ Dyalog APL Vision ∙ dzaima/APL ∙ GNU APL ∙ Kap ∙ NARS2000 ∙ Pometo |
Historical | A Programming Language ∙ A+ (A) ∙ APL# ∙ APL2C ∙ APL\360 ∙ APL/700 ∙ APL\1130 ∙ APL\3000 ∙ APL.68000 ∙ APL*PLUS ∙ APL.jl ∙ APL.SV ∙ APLX ∙ Extended Dyalog APL ∙ Iverson notation ∙ IVSYS/7090 ∙ NARS ∙ ngn/apl ∙ openAPL ∙ Operators and Functions ∙ PAT ∙ Rowan ∙ SAX ∙ SHARP APL ∙ Rationalized APL ∙ VisualAPL (APLNext) ∙ VS APL ∙ York APL |
Derivatives | AHPL ∙ BQN ∙ CoSy ∙ ELI ∙ Glee ∙ I ∙ Ivy ∙ J ∙ Jelly ∙ K (Goal, Klong, Q) ∙ KamilaLisp ∙ Lang5 ∙ Lil ∙ Nial ∙ RAD ∙ Uiua |
Overviews | Comparison of APL dialects ∙ Timeline of array languages ∙ Timeline of influential array languages ∙ Family tree of array languages |