Skip to main content

aplnb

aplnb brings MiniAPL to Jupyter and IPython. Use %%apl for APL session output and %apl for native MiniAPL values in Python. Both share a persistent workspace.

See core for the implementation. For the J language, see the sibling project jnb.

Installation

Install aplnb and its MiniAPL runtime:

pip install aplnb

No separate APL installation is needed. To load the magics automatically in IPython and Jupyter, run:

aplnb_install

Or run %load_ext aplnb in an individual notebook. The interpreter starts on the first use of a magic.

Native arrays

The line magic %apl returns a native basedpl.Array. Its immutable data stays in MiniAPL, retaining nesting, exact numbers and empty-array prototypes. No NumPy conversion is needed:

v = %apl 1 2 4
v
[1., 2., 4.]

Python operators use MiniAPL’s array semantics. Python determines precedence, so this multiplies before adding:

v * 2 + 1
[3., 5., 9.]

Indexing is one-based, as in APL. A full : selects an axis. Iteration yields rows of a matrix rather than individual elements:

a = %apl 2 3⍴⍳6
a.shape, a[1, :], a[:, 2], list(a)
((2, 3), [1., 2., 3.], [2., 5.], [[1., 2., 3.], [4., 5., 6.]])

MiniAPL also exposes functions by their word names. plus.reduce() is +/; adding .each() applies it to each nested element:

from basedpl import Array, plus, tally
nested = %apl (1 2)(3 4 5)
nested, plus.reduce().each()(nested)
([Array([1., 2.]), Array([3., 4., 5.])], [3., 12.])

Python integers become exact values. Functions compose too: plus.reduce() / tally builds the mean function +/÷≢. Its result is still a native array, even when scalar:

exact = Array([1, 2, 4])
mean_native = plus.reduce() / tally
mean_native(exact)
Fraction(7, 3)

The native representation uses Python numeric notation: 2 is exact and 2. is approximate. .apl returns the APL display as a string:

v.apl, exact.apl
('1 2 4', '1x 2x 4x')

The apl magics

Hold left Alt/Option for MiniAPL’s glyph keyboard: Alt-h , Alt-minus ×, Alt-equals ÷, Alt-Shift-a . Right Option keeps its native behavior. Chords work in APL input, including strings and comments.

Type a backtick followed by a MiniAPL symbol name: `io then Tab inserts , and 2`times3 becomes 2×3. Suggestions appear beside the cursor as you type. Click a suggestion or keep typing to resolve an ambiguous name. Names and aliases come from MiniAPL’s REPL catalogue.

Completion is active in %%apl cells and on %apl lines, including x = %apl .... Ordinary Python and Markdown input is unchanged. Strings, comments and pasted text are not expanded. Tab explicitly completes an existing name. Enter accepts a unique match before the notebook’s normal newline or execution action. Escape or cursor movement cancels automatic expansion.

The first apl magic also adds a clickable symbol bar, based on Adám Brudzewsky’s APL language bar. Hover over a glyph to see its names. The / button switches between pushing the page down and overlaying it. This choice is remembered per site.

The cell magic (%%apl) displays MiniAPL session output in Adám’s SAX2 APL font:

%%apl
m3 3⍴⍳9
m×10
10 20 30
40 50 60
70 80 90

Assignments are shy: the m← line printed nothing. The line magic returns a native array. Use .np for a NumPy array; install NumPy with pip install numpy to run the conversion examples:

v = %apl 3×⍳4
v.np
array([ 3.,  6.,  9., 12.])
text = %apl 'APL in Python'
text.py
'APL in Python'

.py converts numeric scalars to Python numbers and character vectors to strings. Other arrays become NumPy arrays. .np always returns a NumPy array. Both conversions copy the data:

z = %apl m
z.np
array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]])

To suppress a cell’s output, end the last line with a ;:

%%apl
m×10;

⎕← displays a value explicitly, which is how you show something that would otherwise be shy:

%%apl
v2×⍳5
⎕←v
2 4 6 8 10

Convert to NumPy to use its methods:

a = %apl m
a.np.sum(axis=0)
array([12., 15., 18.])

Example algorithms

The fibonacci sequence:

fib = %apl {,+/¯2↑⍵}151 1
fib.np
array([1.000e+00, 1.000e+00, 2.000e+00, 3.000e+00, 5.000e+00, 8.000e+00,
       1.300e+01, 2.100e+01, 3.400e+01, 5.500e+01, 8.900e+01, 1.440e+02,
       2.330e+02, 3.770e+02, 6.100e+02, 9.870e+02, 1.597e+03])

Explanation:

  1. 1 1: Initial seed (first two Fibonacci numbers)
  2. {⍵,+/¯2↑⍵}: Function that appends the sum of the last two elements
  3. ⍣15: Apply the function 15 times
  4. : Identity function, passes the initial argument (1 1) to the iteration

Prime number sieve:

%%apl
primes  {⍵×2=+0=⍵∘.|}
(primes 50)~0
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Explanation:

  1. ⍳50 generates integers 1 to 50
  2. ⍵∘.|⍵ creates a matrix of remainders, with candidate divisors in the rows
  3. 0= marks the entries with no remainder
  4. +⌿ sums columns, counting divisors for each number
  5. 2= selects numbers with exactly two divisors
  6. ⍵× keeps those numbers and replaces the rest with zero
  7. ~0 removes the zeros

Using MiniAPL from Python

The magics use basedpl.Session. Calling a session returns a native array or function and prints explicit APL output. apl.eval(...) returns a Result with the native .value and captured .output without printing. Both suppress implicit APL display. Use .np or .py when you need a converted result:

import numpy as np
from basedpl import Session
apl = Session()
apl('3 3⍴⍳9').np
array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]])

Keyword arguments bind Python values in the workspace. Square brackets read an APL expression or assign a value:

apl(x=np.arange(1, 6))
apl['v'] = [3,1,4,1,5]
apl['{⍵[⍋⍵]}v'].np
array([1, 1, 3, 4, 5])

fn makes a composable Function from an APL function expression. Pass one argument for a monadic call or two for a dyadic call. Python integers stay exact, so .py converts this mean to a Fraction rather than a float:

mean = apl.fn('{(+/⍵)÷≢⍵}')
mean([1,2,4]).py
Fraction(7, 3)

fn is late-bound: apl.fn('foo') follows later redefinitions of foo. Use create_magic(session=apl) to share a Python session with the magics.

Use a session as a context manager (with Session() as apl:), or close it when finished:

apl.close()

Dyalog reference sessions

Use aplnb.dyalog when you need Dyalog as an independent reference interpreter. Dyalog must be installed separately. This session API does not change the %apl or %%apl magics, which continue to use MiniAPL:

from aplnb.dyalog import Apl
with Apl() as dyalog:
    total = dyalog.pyval('+/⍳10')
total
55

pyval returns JSON-converted Python values. run returns session output as text. See Dyalog sessions for assignment, function calls and error handling.

Errors and interruption

APL errors raise basedpl.AplError. The magics display output produced before the error. Incomplete input raises a syntax error without resetting the workspace.

Interrupt a calculation with the notebook’s stop button. Set a per-evaluation deadline with Session(timeout=seconds) or magic.session.timeout = seconds. Sessions use a Rust worker thread. Cooperative cancellation preserves the workspace and completed assignments. Native-library calls and individual BigInt operations can delay cancellation; the thread is never forcibly killed.

MiniAPL implements a subset of Dyalog APL. See its README for supported language features and differences.

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. Interpreter-specific features and user commands differ in MiniAPL.

Release files for aplnb 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aplnb 0.3.0
File Size Uploaded
aplnb-0.3.0.tar.gz 28.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aplnb 0.3.0
File Interpreter ABI Platform
aplnb-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 52.5 kB

Release files / aplnb-0.3.0.tar.gz

Download URL aplnb-0.3.0.tar.gz
Size 28.2 kB
Tags Source
SHA-256 checksum
How to use checksums
df3fe5c4965583bb3ea6ab92d46dbb49b71a5992e2e75dc8c702a7fd28e5ec68
BLAKE2b-256 checksum
How to use checksums
82e1670b0fa6968b689e423f14fb11a9fd0334da782d60c9ac1727be40bccb9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / aplnb-0.3.0-py3-none-any.whl

Download URL aplnb-0.3.0-py3-none-any.whl
Size 24.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d53dee11ddfce17a792a81821e3a71eb4eb94f493e354486180497fa002216c8
BLAKE2b-256 checksum
How to use checksums
753048c3288a10a90aedb3c5b17b84255928c4cb67563f73f782d12ecaae9231
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

0.3.2

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page