•prefs — Session settings
•prefs Y applies the settings in the record Y for the whole process, and returns every setting except seed. The result is shy when Y sets something, as an assignment’s is. •prefs ⍬ changes nothing, and shows every setting.
| Setting | Holds | Default |
|---|---|---|
box |
$t draws matrices and nested arrays in boxes. Simple vectors and strings stay plain |
$t in the REPL, the BPL Jupyter kernel and IPython once it loads BPL’s magics, $f elsewhere |
trees |
$t shows functions and dissected expressions as trees; $f uses linear notation. Independent of box |
as box |
fns |
$f leaves output made inside functions unboxed |
as box |
dissect |
$t shows the bound expression before each normal result, using trees |
$f |
fusion |
$t writes a line for each call that ends a fused computation, as described below |
$f |
limit |
The most items display shows in full. ∞ shows every item |
1000 |
edges |
Positions shown at each end of a long axis | 3 |
prec |
Significant digits shown for each float. ∞ shows every digit |
10 |
width |
The widest line display shows. ∞ allows any width |
The terminal’s width in the REPL, ∞ elsewhere |
notation |
Generated function and operator notation: "apl", "simplified" or "traditional" |
"apl" |
hanzi_aliases |
$t enables Hanzi glyph aliases. Other Hanzi remain name characters. Requires a leading declaration on a literal record |
$f |
mathish |
$t applies Mathish mode to Mathish types under dynamic kinds |
$t |
float |
The width of new floats in bits, 16, 32 or 64 | 64 |
kinds |
"static" makes each result’s kind follow from its arguments’ kinds and these settings alone. "dynamic" lets some functions choose it from values, as described below |
"dynamic" |
int |
The width of integers in bits under static kinds, 32 or 64 | 32 |
threads |
The number of threads that large calls split across. 0 gives the default. 1 keeps every call on one thread |
0 |
batch |
$t lets each map call its operand once on all its cells together, as described below |
$t |
seed |
A nonnegative whole number that seeds the session’s random numbers | A seed from the operating system |
Display shows part of an array of more than limit items: the first and last edges positions of each axis longer than twice edges. … replaces hidden columns, ⋮ hidden rows, and ⋱ sits where they cross. A nested array follows the same rule on its own. So does an array that a function holds, such as ⍳10000 in (⍳10000)↣+. A line wider than width keeps as many positions at each end as fit.
Character vectors display as quoted strings, including inside arrays and with box on. Embedded quotes are doubled and line breaks stay as line breaks. Other control characters display as escapes such as \t. limit counts characters in a single-line string and lines in a multiline string. A preview keeps a prefix and up to edges trailing characters or lines, with … or a ⋮ line between. At least half the budget goes to the prefix. Long lines use the same prefix-and-tail rule to fit width.
⎕← always shows every item and rounds floats to prec as display does. ⍕ and source text always hold every item and every digit. "-" •nput text writes raw text without quotes or truncation.
notation changes generated function and operator displays, including trees and dissected expressions. Dfn source, strings, record keys and field separators stay unchanged. Generated source and structural APIs keep canonical APL spellings.
hanzi_aliases controls accepted input independently of notation. Put •prefs ["hanzi_aliases":$t] before any other code to enable Hanzi glyph spellings. The setting persists across notebook cells and REPL inputs. Loaded files use and update the same preferences as their caller. See Hanzi spellings.
Static calculations ignore mathish. •prefs ⍬ still reports its configured value.
float sets the default width of floats, in bits: the width of bare numbers in code parsed after the change, of numbers that •csv, •json, •vfi and •image read, of random numbers, and of floats that a function gives from exact arguments. Until float is set, that width follows kinds: 64 bits under dynamic kinds and 32 under static kinds. Once set, it holds under both. Code already parsed keeps its numbers. A change partway through some code therefore applies from the next input, or from text that ⍎ parses later. Leading •prefs calls on a literal record are the exception. They run before the rest of their code is parsed, as in the examples below. A script, a notebook cell, a line typed at the REPL, a module that •load runs and text that ⍎ runs can each set its own width this way. See Numbers.
kinds sets whether a result’s kind can depend on its arguments’ values. Under the default, "dynamic", √¯4 gives 0ⱼ2, 1j0 reads as the float 1, ⌊2.5 gives the exact integer 2, 7ₓ÷2ₓ gives 7ᵣ2, and exact integers grow without limit. Under "static", each result’s kind follows from the function, its arguments’ kinds and these settings. Real arguments give real results, with NaN outside a function’s domain. Complex results stay complex. ⌊, ⌈ and monadic × of floats give floats, and integer ÷ gives floats, where ⌊ₓ, ⌈ₓ, ×ₓ and ÷ₓ give integers, converting as Rust’s as does. Integers compute at the int width, or at a wider integer’s width, and wrap where a result doesn’t fit. Exact fractions stay exact. An integer beside a float takes the float’s width. An atom promotes as an array does. Fused computations and a GPU need each result’s kind before they run, and under static kinds more calls fuse, as the examples under fusion show. A literal reads under the settings in force when its code is parsed, as with float. See Numbers.
threads sets how many threads large calls split across. A call splits only when it has enough work to repay the extra threads. Float results can differ in their last bits between thread counts. The default, 0, uses the number in the RAYON_NUM_THREADS environment variable where it’s set, and one thread for each core otherwise. 1 runs every call on the thread that evaluates the code. When several BPL processes run at once, such as a pool of Python workers, set 1 in each of them to keep them from competing for the cores. The browser build runs every call on one thread, whatever the setting.
With batch on, a map calls its operand once on all its cells together where it can, as Evaluation describes. With batch set to $f, every map calls its operand once for each cell. Results are the same either way.
seed restarts the session’s random numbers from the seed given, so the same seed gives the same draws of ¿ and of a distribution’s sample. The settings that •prefs returns leave seed out, because the stream moves on with each draw. Restoring saved settings therefore never reseeds it.
fusion shows where large computations stop waiting. Calls of these glyphs on arrays of 65,536 numbers or more run together, block by block, reading each array once: monadic + - ÷ | * π ⊼ ⊽ ≤ ≥, and dyadic + - × ÷ | ⌈ ⌊ π and the comparisons. Under dynamic kinds, √ and ⍟ join them where earlier calls keep their argument from being negative or ¯0, as in √|y and ⍟1+*y, and so do dyadic * on such a base, as in 0.5*y, and dyadic ⍟ on two such arguments. So do calls on Booleans, such as ∧ and ~, and calls on integers where integers wrap: under static kinds, and at a fixed width under either kinds. A width or fixed mark, or •float, on a waiting result runs with its calls, and stores only the converted items. A comparison runs with a later call that reads it, as in y×x>0, unless a name also holds it. Structural functions such as ⌽, ⍉, ↑, ↓ and ↕ wait too on arrays of that size and of any kind, holding only where each item of their result comes from in their argument. Each call waits until something reads its result. A call that would make a chain of waiting calls hold more than 64 calls, or keep alive more than 8 times its largest array, first computes the waiting results it reads. Fused calls, reductions, other pervasive calls and +.× read a waiting structural result from its argument, without building it. A read of a few items computes only those items. Any other reader computes the whole result first, such as ⍋, display, and Python conversions other than NumPy views of structural results. With fusion set to $t, the innermost call that computes items of a waiting result writes a line naming its function and position, such as fusion ends at ⍋ (<input>:1:46). A reduction such as +/ of a waiting result runs with the calls and writes nothing. Performance explains how waiting calls, compiling and static kinds make code fast.
•explain records the same events. In the first example, the comparison runs with the arithmetic and +/. In the second, monadic ⌊ ends the fusion of y×2. In the third, | keeps the argument of √ from being negative, so √ runs with the other calls:
y←¿1000000⍴0
(•explain "+/ y+1 < |y-0.5").fused.glyphs ⍝ ["-|+<+/"]
(•explain "+/⌊y×2").forced.function ⍝ ["⌊"]
(•explain "+/√|y-0.5").fused.glyphs ⍝ ["-|√+/"]A waiting call keeps the settings in force when it was called. Here a comparison waits under Mathish mode’s tolerance, and still uses it after the setting changes:
y←1+¿200000⍴0
c←y=y+1E¯15
•prefs ["mathish":$f]
+/c ⍝ 200000ₓ
+/y=y+1E¯15 ⍝ 0ₓ
•prefs ["mathish":$t]A call fuses when it can’t fail and its kernel gives the type that the call computes at, or Booleans, so that its result’s type doesn’t depend on its items. This example checks the list above against the monadic and dyadic forms of each numeric glyph. Halves of small integers keep ∨ and ∧ quick. Under static kinds, every monadic glyph in the list fuses except ○, whose results are complex, and +, which gives floats back unchanged, so there’s no call to fuse. There, the kernels give NaN or floats where dynamic kinds would rerun a call on complex numbers or give integers, so they can’t fail:
y←0.5׿200000⍴100
fuses←{0ₓ<≢(•explain ⍵).fused.glyphs}
monads←"+-×÷|⌈⌊*⍟√!○π⊼⊽≤≥"
dyads←"+-×÷|⌈⌊*⍟√!π∨∧=≠<≤>≥"
{fuses "+/",⍵,"y"}¨monads # monads ⍝ "+-÷|*π⊼⊽≤≥"
{fuses "+/0.5",⍵,"y"}¨dyads # dyads ⍝ "+-×÷|⌈⌊*π=≠<≤>≥"
•prefs ["kinds":"static"] ⋄ {fuses "+/",⍵,"y"}¨monads # monads ⍝ "-×÷|⌈⌊*⍟√!π⊼⊽≤≥"
•prefs ["kinds":"dynamic"]•prefs ["mathish":$f] ⋄ 0.3=0.1+0.2 ⍝ $f
•prefs ["mathish":$t] ⋄ 0.3=0.1+0.2 ⍝ $t
1ₛ=1.0000001ₛ ⍝ $f
•prefs ["kinds":"static"] ⋄ (•storage 1.5).kind ⍝ "float32"
•prefs ["float":32] ⋄ (•storage 1.5).kind ⍝ "float32"
•prefs ["float":64] ⋄ (•storage 1.5).kind ⍝ "float64"
•prefs ["threads":1] ⋄ "threads"⊃•prefs ⍬ ⍝ 1ₓ
•prefs ["kinds":"static"] ⋄ √¯4 ⍝ $n
•prefs ["kinds":"static"] ⋄ 2147483647ₓ+1ₓ ⍝ ¯2147483648ₓ
•prefs ["int":64] ⋄ 2147483647ₓ+1ₓ ⍝ 2147483648ₓ
•prefs ["kinds":"dynamic" "int":32] ⋄ √¯4 ⍝ 0ⱼ2
•prefs ["seed":42] ⋄ a←¿6 6 6 ⋄ •prefs ["seed":42] ⋄ a≡¿6 6 6 ⍝ $tErrors: DOMAIN for an unknown setting or an invalid value. Under static kinds, LIMIT for an exact integer literal that doesn’t fit the int width, or for a count or position that doesn’t fit it.