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)
Array((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

The built-in prime glyph returns the nth prime, counting from one. Applied to ⍳15, it produces the same list directly:

%%apl
15
2x 3x 5x 7x 11x 13x 17x 19x 23x 29x 31x 37x 41x 43x 47x

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.1

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.1
File Size Uploaded
aplnb-0.3.1.tar.gz 28.5 kB Details

Built distribution (wheel)

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

Total release size: 53.0 kB

Release files / aplnb-0.3.1.tar.gz

Download URL aplnb-0.3.1.tar.gz
Size 28.5 kB
Tags Source
SHA-256 checksum
How to use checksums
882351aa173a998159c717382c9d01ce2a63b78ca2ebe5305e263188ffe7eb7f
BLAKE2b-256 checksum
How to use checksums
9b15694f70752a7fbab4f4dc229249769a6b357eeac433cd2e14ac1b974ec4cf
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.1-py3-none-any.whl

Download URL aplnb-0.3.1-py3-none-any.whl
Size 24.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08bf51abc336392d6ae74a16dda0d01f939415f3971fc4bffb28c3719124f3e0
BLAKE2b-256 checksum
How to use checksums
502664cde5b56bd01fe942635a7e3640e53a1aecb62359d3a9587abf72f08512
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

This release

0.3.1 This release

2 release files

0.3.0

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