x←10
[x x+1 "hi"]10 11 "hi"
BPL has two kinds of value. Numbers, characters and functions are atoms. An array is a rectangular collection of values, including other arrays. This is the based array model, named in a 1981 paper and popularized by BQN.
Write a vector by putting its items in brackets, separated by spaces. An item can be any expression without a space in it, such as a number, a name, x+1 or a string:
A bracket list is a vector, however many items it has. Shape, monadic ⍴, shows that [5] has one axis of length 1, where the number 5 has none:
A list of literals can leave its brackets out. Values written side by side form a strand, the same vector as the bracket list:
Names side by side form a strand too:
Matrices are written in brackets too, one row per line. Types of brackets covers this array notation, along with what ; and ⋄ mean inside brackets:
An array’s shape lists the lengths of its axes. Its rank is the number of axes, the tally of its shape. Scalars, vectors and matrices are the arrays of rank 0, 1 and 2. m has two rows and three columns:
Reshape, dyadic ⍴, builds an array of any shape from the items on its right. ⍳6 counts from 0 to 5:
An axis can have length 0. This matrix has no rows and three columns:
Ravel, monadic ,, lists the items in row-major order:
Neither an atom nor a scalar, the array of rank 0, has any axes. Enclose, ⊂, gives a scalar holding its argument:
They’re still different values. A scalar is an array with one position, holding the atom:
Enclosing always adds a layer, even around an atom. Depth, monadic ≡, counts the layers:
⊂ encloses only subjects. For a function f, the scalar holding it is fᵘ:
The items of an array can be arrays. This vector holds two vectors of different lengths:
First, monadic ↑, gives the first item. Each, ¨, applies a function to every item, here Tally, ≢:
n, a vector of vectors of numbers, has depth 2:
Arithmetic, Each and indexing keep the container they map over, even a scalar:
Rank and the search functions work on whole cells instead, as Rank describes.
Every array has a prototype, which gives its fill. The fill is zero for numbers, a space for characters, and a filled copy of the first item for nested arrays. Take, dyadic ↑, pads with fill when it asks for more items than there are:
An empty array keeps its prototype. First of this empty vector gives the fill of 1 2, the first item of the vector it came from:
When results of different lengths are assembled into one array, the shorter ones are padded with fill. {1+⍳⍵}⍤0 gives one row per count:
Each keeps the results as separate items instead:
Keys label the positions along an axis. Write them with :, then pick an item by its key with a dot:
Axes can also have names. A shape with keys names the axes Reshape builds. Axis keys covers keyed arrays in full:
An array can hold functions. fs is a vector of three:
Selecting an item gives back a function you can call. A subscript selects one position:
Pick, ⊃, First, ↑, and Index, ⌷, with a single position also return stored functions. ↑⌽fs is the last one:
A list can mix functions with other values, including a vector of functions as one item:
Successive Picks go down into nested arrays. Empty coordinates return the argument unchanged:
A dfn can return a function it selects. Agenda selects one and calls it in one step:
Function items are shared handles, not source text. Reshape, selection, catenation and the other structural functions move them without running them. Display prints each function as its source. A native function with no source spelling, such as a generator’s roll, prints in ⟨…⟩. A function’s fill is the function itself, which Take shows:
Two functions match when they’re built from matching parts. A primitive matches itself, as does a derived function such as +/, however many times either is written. A dfn matches only itself. Two separately written {⍵} don’t match, even though they do the same thing. Functions have no ordering, and Grade and Interval Index reject them.
A dfn can return a function. A local function it captures works while the call that defined it is still running. Returning it, or storing it anywhere that outlives the call, including inside an array or an empty prototype, is a DOMAIN error.
In Python, arrays of functions work as Callable functions describes.