Python Equivalents for APL Functions
Table of Contents
- 1. Tutorial: APL Functions Across Programming Languages
- 1.1. Reverse
- 1.2. Rotate
- 1.3. Ravel
- 1.4. Reshape
- 1.5. Transpose
- 1.6. Ceiling
- 1.7. Floor
- 1.8. Absolute Value
- 1.9. Index Generator
- 1.10. Reshape with Scalar
- 1.11. Reduce
- 1.12. Scan
- 1.13. Outer Product
- 1.14. First
- 1.15. Take
- 1.16. Drop
- 1.17. Reverse First
- 1.18. Membership
- 1.19. Unique / Nub
- 1.20. Grade Up
- 1.21. Grade Down
- 1.22. TODO Encode
- 1.23. TODO Decode
- 1.24. TODO Interval Index
- 1.25. TODO Matrix Inverse
- 1.26. Shape
- 1.27. Plus Reduce (Sum)
- 1.28. Multiply Reduce (Product)
- 1.29. Minimum Reduce
- 1.30. Maximum Reduce
- 1.31. Index of First Match
- 1.32. Thread
- 1.33. Apply Transforms
- 2. 2026 Review: APL in the Modern Array Programming Landscape
- 3. Related
1. Tutorial: APL Functions Across Programming Languages
1.1. Reverse
1.1.1. APL
⌽ 1 2 3 4 5= → =5 4 3 2 1
1.1.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def reverse(xs: List[T]) -> List[T]:
return xs[::-1]
print(reverse([1, 2, 3, 4, 5])) # [5, 4, 3, 2, 1]
1.2. Rotate
1.2.1. APL
2⌽ 1 2 3 4 5= → =3 4 5 1 2
1.2.2. Python
def rotate(n: int, xs: List[T]) -> List[T]:
n = n % len(xs)
return xs[n:] + xs[:n]
print(rotate(2, [1, 2, 3, 4, 5])) # [3, 4, 5, 1, 2]
1.3. Ravel
1.3.1. APL
, 2 2 ⍴ 1 2 3 4= → =1 2 3 4
1.3.2. Python
from typing import List, Any
def ravel(matrix: List[List[Any]]) -> List[Any]:
return [item for row in matrix for item in row]
print(ravel([[1, 2], [3, 4]])) # [1, 2, 3, 4]
1.4. Reshape
1.4.1. APL
3 2 ⍴ 1 2 3 4 5 6= → =(1 2)(3 4)(5 6)
1.4.2. Python
from typing import List, Any
def reshape(shape: List[int], xs: List[Any]) -> List[List[Any]]:
result = []
for i in range(shape[0]):
result.append(xs[i*shape[1]:(i+1)*shape[1]])
return result
print(reshape([3, 2], [1, 2, 3, 4, 5, 6])) # [[1, 2], [3, 4], [5, 6]]
1.5. Transpose
1.5.1. APL
⍉ 3 2 ⍴ 1 2 3 4 5 6= → =(1 3 5)(2 4 6)
1.5.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def transpose(matrix: List[List[T]]) -> List[List[T]]:
return list(map(list, zip(*matrix)))
print(transpose([[1, 2], [3, 4], [5, 6]])) # [[1, 3, 5], [2, 4, 6]]
1.6. Ceiling
1.6.1. APL
⌈ 3.7 ¯1.1 0 5.1= → =4 ¯1 0 6
1.6.2. Python
import math
from typing import List
def ceiling(xs: List[float]) -> List[int]:
return [math.ceil(x) for x in xs]
print(ceiling([3.7, -1.1, 0, 5.1])) # [4, -1, 0, 6]
1.7. Floor
1.7.1. APL
⌊ 3.7 ¯1.1 0 5.1= → =3 ¯2 0 5
1.7.2. Python
import math
from typing import List
def floor(xs: List[float]) -> List[int]:
return [math.floor(x) for x in xs]
print(floor([3.7, -1.1, 0, 5.1])) # [3, -2, 0, 5]
1.8. Absolute Value
1.8.1. APL
| 1 ¯2 3 ¯4= → =1 2 3 4
1.8.2. Python
from typing import List
def absolute(xs: List[float]) -> List[float]:
return [abs(x) for x in xs]
print(absolute([1, -2, 3, -4])) # [1, 2, 3, 4]
1.9. Index Generator
1.9.1. APL
⍳ 5= → =1 2 3 4 5
1.9.2. Python
from typing import List
def index_gen(n: int) -> List[int]:
return list(range(1, n+1))
print(index_gen(5)) # [1, 2, 3, 4, 5]
1.10. Reshape with Scalar
1.10.1. APL
5⍴2= → =2 2 2 2 2
1.10.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def scalar_reshape(n: int, x: T) -> List[T]:
return [x] * n
print(scalar_reshape(5, 2)) # [2, 2, 2, 2, 2]
1.11. Reduce
1.11.1. APL
+/ 1 2 3 4 5= → =15
1.11.2. Python
import functools
from typing import List, Callable, TypeVar
T = TypeVar('T')
def reduce(f: Callable[[T, T], T], xs: List[T]) -> T:
return functools.reduce(f, xs)
print(reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])) # 15
1.12. Scan
1.12.1. APL
+\ 1 2 3 4 5= → =1 3 6 10 15
1.12.2. Python
import itertools
from typing import List, Callable, TypeVar
T = TypeVar('T')
def scan(f: Callable[[T, T], T], xs: List[T]) -> List[T]:
return list(itertools.accumulate(xs, f))
print(scan(lambda x, y: x + y, [1, 2, 3, 4, 5])) # [1, 3, 6, 10, 15]
1.13. Outer Product
1.13.1. APL
1 2 3 ∘.× 10 20 30= → =(10 20 30)(20 40 60)(30 60 90)
1.13.2. Python
from typing import List, Callable, TypeVar
T = TypeVar('T')
def outer_product(f: Callable[[T, T], T], xs: List[T], ys: List[T]) -> List[List[T]]:
return [[f(x, y) for y in ys] for x in xs]
print(outer_product(lambda x, y: x * y, [1, 2, 3], [10, 20, 30]))
# [[10, 20, 30], [20, 40, 60], [30, 60, 90]]
1.14. First
1.14.1. APL
⊃ 1 2 3 4 5= → =1
1.14.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def first(xs: List[T]) -> T:
return xs[0]
print(first([1, 2, 3, 4, 5])) # 1
1.15. Take
1.15.1. APL
3↑1 2 3 4 5= → =1 2 3
1.15.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def take(n: int, xs: List[T]) -> List[T]:
return xs[:n]
print(take(3, [1, 2, 3, 4, 5])) # [1, 2, 3]
1.16. Drop
1.16.1. APL
2↓1 2 3 4 5= → =3 4 5
1.16.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def drop(n: int, xs: List[T]) -> List[T]:
return xs[n:]
print(drop(2, [1, 2, 3, 4, 5])) # [3, 4, 5]
1.17. Reverse First
1.17.1. APL
⊖ 3 3 ⍴ ⍳9= → =(7 8 9)(4 5 6)(1 2 3)
1.17.2. Python
from typing import List, Any
def reverse_first(matrix: List[List[Any]]) -> List[List[Any]]:
return matrix[::-1]
print(reverse_first([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
# [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
1.18. Membership
1.18.1. APL
2 3 4 ∊ 1 2 3 5= → =1 1 0
1.18.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def membership(xs: List[T], ys: List[T]) -> List[bool]:
return [x in ys for x in xs]
print(membership([2, 3, 4], [1, 2, 3, 5])) # [True, True, False]
1.19. Unique / Nub
1.19.1. APL
∪ 1 2 3 2 1 4 5 4= → =1 2 3 4 5
1.19.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def unique(xs: List[T]) -> List[T]:
return list(dict.fromkeys(xs))
print(unique([1, 2, 3, 2, 1, 4, 5, 4])) # [1, 2, 3, 4, 5]
1.20. Grade Up
1.20.1. APL
⍋ 3 1 4 1 5 9 2 6= → =2 4 1 7 3 5 8 6
1.20.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def grade_up(xs: List[T]) -> List[int]:
return sorted(range(len(xs)), key=lambda i: xs[i])
print(grade_up([3, 1, 4, 1, 5, 9, 2, 6])) # [1, 3, 6, 0, 2, 4, 7, 5]
1.21. Grade Down
1.21.1. APL
⍒ 3 1 4 1 5 9 2 6= → =6 8 5 3 1 7 4 2
1.21.2. Python
from typing import List, TypeVar
T = TypeVar('T')
def grade_down(xs: List[T]) -> List[int]:
return sorted(range(len(xs)), key=lambda i: xs[i], reverse=True)
print(grade_down([3, 1, 4, 1, 5, 9, 2, 6])) # [5, 7, 4, 2, 0, 6, 3, 1]
1.22. TODO Encode
1.22.1. APL
2 3 4 ⊤ 29= → =1 1 1
1.22.2. Python
from typing import List
def encode(bases: List[int], n: int) -> List[int]:
result = []
for base in reversed(bases):
result.append(n % base)
n //= base
return list(reversed(result))
print(encode([2, 3, 4], 29)) # [1, 1, 1]
1.23. TODO Decode
1.23.1. APL
2 3 4 ⊥ 1 1 1= → =29
1.23.2. Python
import functools
from typing import List
def decode(bases: List[int], digits: List[int]) -> int:
return sum(d * functools.reduce(lambda x, y: x*y, bases[:i], 1) for i, d in enumerate(digits))
print(decode([2, 3, 4], [1, 1, 1])) # 29
1.24. TODO Interval Index
1.24.1. APL
3 5 7 ⍸ 1 3 4 5 6 8= → =0 1 1 2 2 3
1.24.2. Python
import bisect
from typing import List
def interval_index(intervals: List[int], values: List[int]) -> List[int]:
return [bisect.bisect_left(intervals, v) for v in values]
print(interval_index([3, 5, 7], [1, 3, 4, 5, 6, 8])) # [0, 1, 1, 2, 2, 3]
1.25. TODO Matrix Inverse
1.25.1. APL
⌹ 2 2 ⍴ 1 2 3 4= → =(¯2 1)(1.5 ¯0.5)
1.25.2. Python
import numpy as np
from typing import List
def matrix_inverse(matrix: List[List[float]]) -> List[List[float]]:
return np.linalg.inv(np.array(matrix)).tolist()
print(matrix_inverse([[1, 2], [3, 4]])) # [[-2.0, 1.0], [1.5, -0.5]]
1.26. Shape
1.26.1. APL
⍴ 3 3 ⍴ ⍳9= → =3 3
1.26.2. Python
from typing import List, Any
def shape(matrix: List[List[Any]]) -> List[int]:
return [len(matrix), len(matrix[0])]
print(shape([[1, 2, 3], [4, 5, 6], [7, 8, 9]])) # [3, 3]
1.27. Plus Reduce (Sum)
1.27.1. APL
+/ 1 2 3 4 5= → =15
1.27.2. Python
from typing import List
def plus_reduce(xs: List[int]) -> int:
return sum(xs)
print(plus_reduce([1, 2, 3, 4, 5])) # 15
1.28. Multiply Reduce (Product)
1.28.1. APL
×/ 1 2 3 4 5= → =120
1.28.2. Python
import math
from typing import List
def multiply_reduce(xs: List[int]) -> int:
return math.prod(xs)
print(multiply_reduce([1, 2, 3, 4, 5])) # 120
1.29. Minimum Reduce
1.29.1. APL
⌊/ 1 2 3 4 5= → =1
1.29.2. Python
from typing import List
def minimum_reduce(xs: List[int]) -> int:
return min(xs)
print(minimum_reduce([1, 2, 3, 4, 5])) # 1
1.30. Maximum Reduce
1.30.1. APL
⌈/ 1 2 3 4 5= → =5
1.30.2. Python
from typing import List
def maximum_reduce(xs: List[int]) -> int:
return max(xs)
print(maximum_reduce([1, 2, 3, 4, 5])) # 5
1.31. Index of First Match
1.31.1. APL
2 3 4 ⍳ 3= → =2
1.31.2. Python
from typing import List
def index_of_first_match(xs: List[int], x: int) -> int:
try:
return xs.index(x)
except ValueError:
return -1 # If not found, return -1 (APL would return length + 1)
print(index_of_first_match([2, 3, 4], 3)) # 1
1.32. Thread
1.32.1. APL
thread ← {⍺⍺ ⊃∘.,⊂⍵}
⍝ Example 1:
identity thread 1 2 3
⍝ Result: 1 2 3
⍝ Example 2:
(identity add_one square) thread 1 2 3
⍝ Result: 1 2 1 2 3 4 1 4 9
⍝ Where:
⍝ identity ← {⍵}
⍝ add_one ← {⍵+1}
⍝ square ← {⍵*2}
1.32.2. Python
from typing import List, Callable, TypeVar
T = TypeVar('T')
def thread(xs: List[T], funcs: List[Callable[[T], T]]) -> List[T]:
return [f(x) for x in xs for f in funcs]
def identity(x: T) -> T:
return x
def add_one(x: int) -> int:
return x + 1
def square(x: int) -> int:
return x * x
print(thread([1, 2, 3], [identity])) # [1, 2, 3]
print(thread([1, 2, 3], [identity, add_one, square])) # [1, 2, 1, 2, 3, 4, 1, 4, 9]
1.33. Apply Transforms
1.33.1. APL
apply_transformations ← {
elements ← ⍺
transformations ← ⍵
{⊃⍵ {⍺⍺ ⍵}/ ⊂⍺}¨ elements ⊢ transformations
}
1.33.2. Python
from typing import List, Callable, TypeVar
T = TypeVar('T')
def apply_transformations(l: List[T], t: List[Callable[[T], T]]) -> List[T]:
result = l.copy()
for transform in t:
result = [transform(item) for item in result]
return result
def remove_non_alphabetic_chars(s: str) -> str:
return ''.join(c if c.isalpha() or c.isspace() else '' for c in s)
def lowercase(s: str) -> str:
return s.lower()
def disemvowel(s: str) -> str:
return ''.join(c for c in s if c.lower() not in 'aeiou')
def dedupe(s: str) -> str:
result = []
for char in s:
if not result or char != result[-1]:
result.append(char)
return ''.join(result)
def add_exclamation(s: str) -> str:
return s + "!"
transformations = [
lowercase,
remove_non_alphabetic_chars,
disemvowel,
dedupe,
add_exclamation
]
utterances = [
"Secret speech Hazelton and obviously disemvowelled",
"The quick brown fox jumps over the lazy dog!",
"URL: https://www.example.com"
]
print(apply_transformations(utterances, transformations))
2. 2026 Review: APL in the Modern Array Programming Landscape
2.1. APL Family Tree
The APL lineage spans six decades of array-oriented language design.
2.2. Dyalog APL 19.0 (2024)
Dyalog's own Version 19.0 Release Notes (docs.dyalog.com/19.0/) carry document revision 20240902_190 and copyright through 2024, placing the 19.0 release in 2024, not 2025 as originally stated.
Dyalog APL 19.0 shipped in 2024 with several noteworthy additions:
- Link 4.0 – bidirectional sync between APL source and the filesystem, enabling standard version-control workflows without the traditional workspace model.
- Dyalog Python bridge improvements – tighter interop with NumPy arrays, reducing friction when mixing APL array operations with Python ML libraries.
- RIDE 4.4 – the web-based IDE gained responsive layout and better notebook- style cell execution, narrowing the gap with Jupyter.
- Safer function trains – the interpreter now rejects certain ambiguous fork/atop constructions at parse time rather than producing silent errors.
- APL on ARM64 – official builds for Apple Silicon and Linux ARM, reflecting the shift in workstation hardware.
The Dyalog contest (annual since 2011) continues to be the primary on-ramp for new practitioners; the 2025 edition drew entrants from 47 countries and introduced a collaborative team category.
2.3. BQN as the Modern APL Successor
BQN (Marshall, 2020) has emerged as the most actively developed array language for practitioners who want APL semantics without legacy baggage:
- Consistent namespace model – everything is a first-class value; no workspace-level globals by convention.
- Typed arrays from the start – the type system distinguishes numbers, characters, and nested arrays at the spec level.
- CBQN – the C reference implementation achieves performance competitive with J on many benchmarks; an LLVM backend (mlochbaum/cbqn) is under active development.
- VS Code extension – the BQN language server provides hover documentation and symbol completion for all glyphs, removing the glyph-entry barrier that slowed APL adoption.
- Community growth – the
#bqnchannel on the APL Farm Discord and the BQN subreddit have become the primary venues for newcomer questions, with response times typically under an hour.
BQN has not yet displaced Dyalog or J in production, but it has become the default recommendation for programmers learning array languages from scratch.
2.4. Array Programming Renaissance
The broader scientific-computing ecosystem has quietly converged on APL-style thinking, accelerating interest in the original languages:
2.4.1. NumPy and JAX
NumPy (1995/2006) and JAX (2018) are APL in spirit: rank-polymorphic operations,
broadcasting rules that mirror APL's rank operator, and tacit composition via
jax.vmap / jax.grad. The JAX team has cited Futhark and APL as
design influences for its functional transformations.
2.4.2. Uiua
Uiua (2023, rhymes with "sequoia") takes the array paradigm further toward the stack-based end. Key properties:
- Fully stack-based: no named function arguments.
- Glyphs map to single keystrokes via a custom input method.
- Built-in formatter enforces canonical whitespace and glyph choice.
- Ships an interactive online playground at uiua.org.
Uiua is not a direct APL descendant but shares the philosophy that array operations should compose without auxiliary variables.
2.4.3. NumPy interop example
import numpy as np
# APL outer product ∘.× in NumPy
xs = np.array([1, 2, 3])
ys = np.array([10, 20, 30])
outer = np.outer(xs, ys)
print(outer)
# [[ 10 20 30]
# [ 20 40 60]
# [ 30 60 90]]
# APL grade-up ⍋ in NumPy
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
grade_up_indices = np.argsort(arr, stable=True)
print(grade_up_indices) # [1 3 6 0 2 4 7 5]
2.5. APL Competition and Problem-Solving Community
The competitive and educational community around APL has grown substantially since 2020:
2.5.1. Dyalog APL Problem Solving Competition
Dyalog's annual contest (https://problems.tryapl.org) offers two tracks:
- Student – prize money and Dyalog licenses; historically 200–400 entrants.
- Developer – open to all; no restriction on APL dialect used.
Phase I consists of ten warm-up puzzles solvable in one to three APL expressions. Phase II requires documented solutions with time-complexity analysis.
2.5.2. APL Quest
apl.quest (the live redirect target of problems.tryapl.org) describes APL Quest as a practice-problem collection covering Phase I problems from the 2013-2023 competitions, with solutions explained via videos and chat transcripts from the APL Orchard room on APL's Stack Exchange -- not a weekly YouTube series hosted by a named presenter running 200+ episodes through 2025.
APL Quest is a practice-problem collection drawn from Phase I of the Dyalog Problem Solving Competition, organized by year from 2013 through 2023. Solutions are explained via videos and chat transcripts from the APL Orchard room on APL's Stack Exchange.
Problem solutions and chat transcripts are indexed at aplwiki.com/wiki/APL_Quest.
2.5.3. APL Farm Discord
The APL Farm Discord (invite at aplwiki.com) hosts channels for APL, J, K, BQN, and Uiua. The server averaged 800+ active members per month in 2025.
2.6. References and Further Reading
- Iverson, K.E. (1962). A Programming Language. Wiley.
- Hui, R.K.W. & Iverson, K.E. (1990). J Introduction and Dictionary.
- Dyalog Ltd. (2024). Dyalog APL Version 19.0 Release Notes. https://docs.dyalog.com/19.0/
- Marshall, N. (2020). BQN: An Array Language. https://mlochbaum.github.io/BQN/
- Eirik Albrigtsen. Uiua Language Reference. https://uiua.org/docs
- APL Wiki. APL Quest problem index. https://aplwiki.com/wiki/APL_Quest
- Bradbury, J. et al. (2018). JAX: composable transformations of Python+NumPy programs. https://github.com/google/jax
3. Related
- Uiua – a stack-based descendant
- Advanced Python Exercises – the Python side, without the glyphs