from fastcore.test import *Dyalog sessions
Import Apl and AplError from basedpl.dyalog. Sessions return Dyalog output or JSON-converted Python values, not BPL arrays. Importing this module does not start Dyalog or register notebook magics.
Install Dyalog separately. The examples use a local interpreter and run with nbdev-test --flags dyalog. The default test run skips them.
Connecting
find_dyalog checks the command path and standard macOS/Linux installation locations. Pass dyalog= to Apl to choose another executable. timeout bounds the startup handshake, not evaluation.
RIDE uses length-prefixed messages over a local socket. ride_run collects session output until Dyalog is ready for another expression. Interactive and incomplete-input prompts are handled by Apl.run.
Evaluating APL
run returns session output as text. Assignments persist across calls:
dyalog = Apl()
out = dyalog.run('x←1 2 3\n+/x')
test_eq(out.strip(), '6')
out'6\n'
Calling a session returns AplOut, the same text with notebook display support. A silent assignment returns None:
test_is(dyalog('quiet←7'), None)
dyalog('2×x')2 4 6
Python values
pyval uses Dyalog’s JSON conversion. Scalars become Python values and numeric arrays become lists. This is the interface used by the reference checker:
test_eq(dyalog.pyval('+/x'), 6)
matrix = dyalog.pyval('2 3⍴⍳6')
test_eq(matrix, [[1,2,3], [4,5,6]])
matrix[[1, 2, 3], [4, 5, 6]]
Square brackets read an expression or assign a JSON-compatible Python value. Quotes in strings are escaped for APL:
dyalog['values'] = [3,1,4]
dyalog['message'] = "can't"
test_eq(dyalog['message'], "can't")
test_eq(dyalog['values'], [3,1,4])
dyalog['values'][3, 1, 4]
fn converts Python arguments through JSON and evaluates the function expression on each call. One argument supplies ⍵; two supply ⍺ and ⍵:
mean = dyalog.fn('{(+/⍵)÷≢⍵}')
test_eq(mean([1,2,3]), 2)
add = dyalog.fn('+')
test_eq(add([1,2,3], 10), [11,12,13])
add([1,2,3], 10)[11, 12, 13]
Errors and lifetime
Dyalog errors raise this module’s AplError, not BplError. Completed assignments remain in the session:
with expect_fail(AplError, contains='DOMAIN ERROR'): dyalog.run('saved←42 ⋄ 1÷0')
test_eq(dyalog['saved'], 42)
dyalog['saved']42
Interactive ⎕ and ⍞ input is rejected. When Dyalog shows an incomplete-input prompt, Apl.run restarts the interpreter and raises AplError with reset=True. The restart loses the workspace.
Call close() when finished, or use a context manager for a bounded reference check:
dyalog.close()
with Apl() as reference: total = reference.pyval('+/⍳10')
test_eq(total, 55)
total55