Language overview

The main ideas of BPL, with examples

BPL code consists of values, functions that apply to them, and operators that make new functions. Code is grouped by spaces and read from right to left. Each term below links to its definition in Terms. The exact rules are in Syntax and Evaluation, with the reasons for them in Language principles.

Values

Every value is an atom or an array. Numbers, characters and functions are atoms. An array is a rectangular collection of values laid out along axes. Here’s a matrix with two rows and three columns:

m←[1 2 3
   4 5 6]
m
1 2 3
4 5 6

Shape, ⍴, gives the length of each axis. The number of axes is the array’s rank:

⍴m
[2 3]ₓ

A vector has one axis:

⍴[10 20 30]
[3]ₓ

The items of an array can be arrays themselves. Depth, ≡, counts the layers of nesting. A number has none:

≡5
0ₓ

⊂ encloses a value in a scalar, an array with no axes. Enclosing always adds a layer, even around a number:

≡⊂5
1ₓ

Arrays covers shape, nesting and fill in depth.

Writing arrays

Brackets are used to write vectors. Each item can be any expression without spaces:

[1 2+3 "hi"]
1 5 "hi"

A one-item vector is still a vector:

⍴[5]
[1]ₓ

Literals separated by spaces form a strand, a list written without brackets:

[1 2 3]≡1 2 3
$t

Inside brackets, a space always separates items. To write an item that contains spaces, separate the items with ; instead:

[1+2;3 4]
[3 [3 4]]

Inside brackets, rows are separated by a line break or ⋄, as in the matrix m above. Types of brackets covers brackets, parentheses and braces.

Reading an expression

Each function takes everything to its right as its right argument, with no precedence between functions. In 2×3+4, × multiplies 2 by the whole sum:

2×3+4
14

Subtraction follows the same rule. 10-3-2 subtracts 3-2 from 10:

10-3-2
9

Spaces group code. A run is a stretch of code with no spaces in it. BPL evaluates each run first, then combines the results from right to left. Here the runs are 2×3, + and 4:

2×3 + 4
10

A function gets one argument or two depending on the value to its left when it runs. With a number on its left, f subtracts:

f←-
5(f)3
2

Subjects side by side form a strand, as literals do:

a←1 2
b←3 4
a b
(1 2 ⋄ 3 4)

Functions, operators and trains

An operator makes a new function from a function or an array. It takes the whole function to its left and one item to its right. Reduce, /, puts its function between the items:

+/1 2 3
6

Each, ¨, applies its function to every item. Here Tally, ≢, counts the characters of each string:

≢¨"ab" "cde"
[2 3]ₓ

A run that ends in a function has no argument. The run is then a function itself, called a train. Three functions in a row form a fork. The fork +/÷≢ divides the sum by the count:

mean←+/÷≢
mean 1 2 3 6
3

A value directly before a function binds to it as its left argument. 2× is the function that doubles:

double←2×
double 5
10

A space before the argument keeps a train separate from it:

x←1 2 3 6
+/÷≢ x
3

Without the space, +/ sums a single number, the reciprocal of ≢x:

+/÷≢x
1ᵣ4

Applying functions to arrays

Arithmetic and comparison are pervasive. They apply to each number in their arguments, through any nesting. A single number pairs with every item:

1 2 3+10
11 12 13

When two arguments have different shapes, BPL lines up their leading axes. An axis of length 1 stretches to match. Adding a two-item vector to the two-row matrix m adds one number to each row:

m+10 20
11 12 13
24 25 26

Rank, ⍤, applies a function to cells of a chosen rank. The 1-cells of a matrix are its rows:

mean⍤1 m
2 5

Axis, ⍠, applies a function along chosen axes. Summing along axis 0 adds down each column:

+/⍠0 m
5 7 9

Selecting

Positions count from 0. Index, ⌷, selects along the leading axis:

v←10 20 30
1⌷v
20

Negative positions count from the end:

¯1⌷v
30

A literal position can also be written as a subscript:

v₁
20

A dot selects an entry of a record by its key:

T←["a":1 "b":2]
T.b
2

Assigning and defining

← assigns to the run just before it, whether that’s a name or a selection:

v₁←7
v
10 7 30

Braces define a function, called a dfn. Inside a dfn, ⍵ is the right argument and ⍺ is the left argument:

sq←{⍵×⍵}
sq 4
16

A dfn can hold alternatives separated by ;, each guarded by a condition ending in ?. It returns the first alternative whose condition holds. The last can leave out its condition to act as the fallback:

abs←{⍵<0?-⍵;⍵}
abs ¯3
3

Assignment, Dfns and Modules cover these in full.