First-class function
A programming language supports first-class functions if it allows functions to be used in the same ways as data values such as numbers and characters. It should be possible to assign functions as variables, pass them as function arguments, and use them as elements of arrays. APL's function application syntax is designed with the assumption that functions are applied to arrays only, not functions. Traditionally, use cases that manipulate functions have been handled with operators, thus making functions second-class (and operators potentially third-class). Mainstream APLs don't support first-class functions as a part of normal programming, although some features such as namespaces and object representations may allow for similar functionality.
Several array languages support first-class functions, with a variety of methods for passing functions as arguments. APL dialects Kap and TinyAPL, as well as BQN, convert APL's function call syntax to a context-free grammar and add features that allow functions to be used in places where arrays are expected grammatically. A+ and the K family (Q, Lil, Goal, Klong) retain APL-like function notation in a limited role, and add a bracket function call syntax that allows functions as arguments. I modifies APL's infix notation to treat functions and arrays equally, and Futhark and KamilaLisp are based on non-APL language families that naturally support functions as arguments.
Related features
While most APLs don't have complete first-class function support, features that allow broader use of functions have been added to APL dialects and related languages over the years:
- Originally only primitives, and not user-defined functions, could be used as operands. Most APLs now support arbitrary operands.
- Function assignment allows function-valued variables. This means first-class namespaces, if supported, can serve as a container for functions.
- Some dialects, including Dyalog APL, allow functions to return functions, as there is no syntax requirement that would prevent it.
- Function arrays can be constructed in Dyalog APL and dzaima/APL (as well as Nial); however, these aren't usable as ordinary arrays.
- In J, a function can be converted to a "gerund", an array that represents it. Various operators accept lists of gerunds and apply the elements as functions.
First-class functions within APL syntax
Kap, TinyAPL, and BQN support first-class functions using syntactic features that allow functions to be transferred into a context typically intended for arrays, and back out. These languages use a context-free grammar so that the syntactic class of each expression is determined as part of parsing (while APL traditionally defines syntactic class as a dynamic property of a value, and the same expression might even take on different classes in different evaluations). Features of first-class functions arise when an expression that parsed as an array has a function value at runtime. Kap and TinyAPL have explicit syntax to "convert" a function expression to the array class, written λ
and ⊏
respectively. BQN uses implicit mechanisms, including the spellings that give a syntactic class to each name: function assignment must use an uppercase name, but later this name can be spelled starting with a lowercase letter to use it as an array. In both TinyAPL and BQN, array notation allows function elements, providing a simple way to create an array containing function elements.
Dyalog APL's object representations work by a similar mechanism, but with dynamic syntax. An object representation may have a function value, but is marked so that it will be treated as an array for parsing purposes. But when an object representation is used as operand, the object represenation is treated as a function, because operator evaluation isn't part of parsing, and checks the value's actual type.