Getting started

Calculate with arrays, then build functions.

Install

Requires Python 3.10 or later. On x86-64, it also requires a CPU with AVX2 (x86-64-v3). Intel CPUs have had AVX2 since 2013 and AMD CPUs since 2015.

pip install basedpl

This installs the bpl command and the basedpl Python package.

First calculations

Run bpl to open the REPL. Type an expression and press Enter. ⍝ starts a comment. The examples use comments to show each result.

BPL evaluates right to left. Parentheses group, and so do spaces. BPL evaluates each part between spaces first.

2×3+4                 ⍝ 14
(2×3)+4               ⍝ 10
2×3 + 4               ⍝ 10
14
10
10

Numbers separated by spaces form a vector. Functions work on every item.

10+1 2 3              ⍝ 11 12 13
11 12 13

⍳ generates indices, ← assigns a name, and +/ sums.

v←⍳5 ⋄ v              ⍝ 0 1 2 3 4
+/⍳5                  ⍝ 10
0 1 2 3 4
10

To enter ⍳5, type backtick, iota, then 5. The digit accepts the glyph and enters the argument. Symbol entry also supports abbreviations and Tab completion.

Numbers and arrays

Bare numbers are approximate. Use ₓ for exact integers and r for fractions.

1÷3                   ⍝ 0.3333333333333333
1ₓ÷3ₓ                 ⍝ 1ᵣ3
0.3333333333
1ᵣ3

j separates real and imaginary parts.

1j2×1j¯2              ⍝ 5
5

⍴ reshapes a vector; +/ sums each row.

+/2 3⍴⍳6              ⍝ 3 12
3 12

Indices start at 0, and negative indices count from the end. Comparisons use a tolerance of 1E¯14. For example, 0.3=0.1+0.2 is true. See the Language overview and the glyph index.

Nested arrays

A bracket list of vectors is a nested vector. Each (¨) applies its operand to each item:

n←[[1 2] [3 4 5]]
+/¨n
3 12

The same Each/reduction pattern works with division:

÷/¨n
0.5 3.75

Example algorithms

Let’s create a function to list primes.

A prime has exactly two positive divisors. The candidates 1↦10 are the numbers 1 to 10. |⊗ is the outer product of remainders. ⍨ passes n as both arguments. Each row below marks the multiples of one candidate:

n←1↦10
0=|⊗⍨n
$t $t $t $t $t $t $t $t $t $t
$f $t $f $t $f $t $f $t $f $t
$f $f $t $f $f $t $f $f $t $f
$f $f $f $t $f $f $f $t $f $f
$f $f $f $f $t $f $f $f $f $t
$f $f $f $f $f $t $f $f $f $f
$f $f $f $f $f $f $t $f $f $f
$f $f $f $f $f $f $f $t $f $f
$f $f $f $f $f $f $f $f $t $f
$f $f $f $f $f $f $f $f $f $t

+⌿ sums down the rows, counting each candidate’s divisors:

+⌿0=|⊗⍨n
[1 2 2 3 2 4 2 4 3 4]ₓ

2= marks the primes. Replicate (#) keeps the items of n that are marked:

2=+⌿0=|⊗⍨n # n
2 3 5 7

A dfn names its argument ⍵. Given the candidates ↦50, the numbers 1 to 50, it lists the primes up to 50:

{2=+⌿0=|⊗⍨⍵ # ⍵}↦50
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Finally, name it. The trailing ↦ generates the candidates:

primes ← {2=+⌿0=|⊗⍨⍵ # ⍵}↦
primes 50
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

The built-in prime glyph ⍭ returns the prime at a position, counting from 0. Applied to ⍳15, it produces the same list directly:

⍭ ⍳15
[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47]ₓ

The fibonacci sequence:

{⍵,+/¯2↑⍵}⍣15 [1 1]
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Explanation:

  1. [1 1]: Initial seed (first two Fibonacci numbers). Without the brackets, 15 1 1 would be one vector.
  2. {⍵,+/¯2↑⍵}: Function that appends the sum of the last two items
  3. ⍣15: Apply the function 15 times

Labelled arrays

An array can have keys for its positions and names for its axes. BPL has no separate table type. Here axes maps each axis name to that axis’s position keys, in axis order. axes: then labels the rows by city and the columns by month:

axes←["city":"NY" "LA";"month":"Jan" "Feb" "Mar"]
sales←axes:[10 20 30⋄40 50 60]
sales
   Jan Feb Mar
NY  10  20  30
LA  40  50  60

⌷ selects by key, with one key for each axis. A single key selects a row. ⍠ applies a function along the axes named by its right operand. Summing over month gives one total for each city, keyed by city.

"LA"⌷sales
"LA" "Feb"⌷sales
+/⍠"month" sales
["month":3]⍴["Jan":40 "Feb":50 "Mar":60]
50
["city":2]⍴["NY":60 "LA":150]

Unlabelled arrays keep their usual positional behaviour. See Axis keys for construction, updates and alignment rules.

CSV and JSON

CSV headers become keys on a vector of columns. Numeric columns use compact storage. These two orders total 101:

orders←•csv "price,qty
10.5,2
20,4"
+/orders.price×orders.qty
101

JSON objects use the same keyed arrays. Parse a record and select a field:

record←•json "{""name"":""Ada"",""scores"":[8,9,10]}"
record.name
+/record.scores
Ada
27ₓ

•json⁻¹ writes the record back as JSON text. For files, compose with •nget and •nput, as in •csv •nget "orders.csv". See files, CSV and JSON for dialect and file options.

•json⁻¹ record
{"name":"Ada","scores":[8,9,10]}

Regex

•r compiles a regular expression into two functions: matches gives a table of each match’s text, position and groups, and replace replaces each match:

codes←•r "([A-Z]+)-([0-9]+)"
codes.matches "AB-12 CD-3"
"$2:$1" codes.replace "AB-12 CD-3"
["text":["AB-12" "CD-3"] "position":[0 6]ₓ "groups":("AB" "12"⋄"CD" "3")]
12:AB 3:CD

Probability distributions

Construct a standard normal, then evaluate its CDF and quantiles. Distribution methods accept arrays:

normal←•distribution "normal"
normal.cdf ¯1 0 1
normal.quantile 0.025 0.5 0.975
0.1586552539 0.5 0.8413447461
¯1.959963985 0 1.959963985

Sampling takes a shape. A generator from •rand on the left makes the draws repeatable:

•rand1 normal.sample 2 3
0.8439986136  0.7155607127 ¯1.915871444 
0.4524964704 ¯0.8157912067  0.3583251372

For discrete distributions, density gives probability mass. A fair coin tossed twice has probabilities ¼, ½, ¼ for zero, one or two heads:

coin←2 0.5 •distribution "binomial"
coin.density 0 1 2
0.25 0.5 0.25

See distributions for the 17 families, and regex for captures and replacement options.

Learning APL

To start learning APL, follow the 17 video series run by Jeremy Howard, and have a look at the study notes. These use Dyalog APL. The main differences from Dyalog are that indices count from 0, brackets are used to write vectors, and spaces group expressions. See the Language overview.