diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-12-21 22:13:32 -0500 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-12-21 22:13:32 -0500 |
| commit | 53beefca49bce6b0eed3f165fb25ae8aae1b8fa2 (patch) | |
| tree | 3d8bc2fa6ce977555424a49fbd2c24db1e026628 /docs | |
| parent | 55c82e40a499c95d6a823c49bbd91f745badadfd (diff) | |
Some remarks on BQN versus APL
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/commentary/why.html | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/docs/commentary/why.html b/docs/commentary/why.html index 7231e1d4..48ed791f 100644 --- a/docs/commentary/why.html +++ b/docs/commentary/why.html @@ -13,6 +13,16 @@ <p>Here are some more specific comparisons against the two most similar languages to BQN. I'll try to bring up the areas where BQN can be considered worse, but my focus here is definitely on BQN's strong points—I'm not trying to offer an unbiased account.</p> <p>BQN is more like APL, but adopts some of the developments made by J as well. However, it's much simpler than both, with fewer and less overloaded primitives as well as less special syntax (J has fewer syntactic rules, but more special cases handled during execution that I think <em>should</em> have been implemented with syntax).</p> <p>The major differences are listed on <a href="../index.html#whats-the-language-like">the front page</a> ("But it's redesigned…"): <a href="../doc/based.html">based arrays</a>, <a href="../doc/arrayrepr.html">list notation</a>, <a href="../doc/context.html">context-free grammar</a> and <a href="../doc/functional.html">first-class functions</a>, <a href="../doc/primitive.html">reworked primitives</a>, and dedicated <a href="../doc/namespace.html">namespace syntax</a>.</p> +<p>In addition to these, BQN's <a href="../doc/block.html">block system</a> extends APL dfns with headers, adding some very useful functionality: the header specifies block type and argument names, and also allows for simple pattern matching when used with multiple block bodies.</p> +<p>Since this section gets into the details, it's worth highlighting stranding, a feature I think of as an obvious improvement but that many BQN newcomers see as an obvious sign that I don't know what I'm doing! I made a longer argument <a href="../doc/arrayrepr.html#why-not-whitespace">here</a>; the two key points are that stranding is a source of ambiguity that can strike at any time, requiring a correction with <code><span class='Function'>⊢</span></code> or <code><span class='Value'>]</span></code>, and that typing <code><span class='Ligature'>‿</span></code> is really not hard I promise.</p> +<p>BQN's heavier-weight <code><span class='Bracket'>⟨⟩</span></code> syntax for lists also has its own advantages, because it can be formatted nicely across multiple lines, and also allows functions and modifiers to be used easily as elements. Being able to easily map over a list of functions is surprisingly useful!</p> +<p>BQN has no built-in control structures, which can be quite an adjustment coming from certain styles of APL or J.</p> +<h3 id="apl"><a class="header" href="#apl">APL</a></h3> +<p>BQN cleans up some awkward syntax left over from when each APL operator was special: the outer product is written <code><span class='Function'>Fn</span><span class='Modifier'>⌜</span></code> rather than <code><span class='Modifier2'>∘</span><span class='Value'>.fn</span></code>, and reduction <code><span class='Function'>Fn</span><span class='Modifier'>´</span> <span class='Value'>arr</span></code> is separated from compress <code><span class='Value'>b</span><span class='Function'>/</span><span class='Value'>arr</span></code>.</p> +<p>BQN adopts <a href="../doc/leading.html">leading axis theory</a> as developed in SHARP APL and applied in A+ and J. With this it can collapse APL pairs such as <code><span class='Function'>⌽</span><span class='Value'>⊖</span></code> and <code><span class='Function'>/</span><span class='Value'>⌿</span></code> to one primitive each, and remove APL's complicated function index mechanism. The Rank modifier <code><span class='Modifier2'>⎉</span></code> then applies these primitives to non-leading axes. While this method is required in J and also favored by many users of Dyalog APL, it definitely doesn't enjoy universal support—it can be harder to learn, and less convenient for some common cases. Summing rows with <code><span class='Function'>+/</span></code> in APL is quite convenient, and BQN's <code><span class='Function'>+</span><span class='Modifier'>˝</span><span class='Modifier2'>⎉</span><span class='Number'>1</span></code>, or <code><span class='Function'>+</span><span class='Modifier'>˝˘</span></code> for matrices, just aren't as nice.</p> +<p>Arguably BQN cuts down the set of primitives too much. Base conversion <code><span class='Value'>⊥⊤</span></code>, partitioning <code><span class='Value'>⊂⊆</span></code>, and matrix division <code><span class='Value'>⌹</span></code> are commonly asked-for primitives, but they don't match <a href="primitive.html">my conception</a> of a primitive. And while each can be implemented (with short snippets, other than <code><span class='Value'>⌹</span></code> which requires a library), there's definitely a convenience loss. But there's always <a href="../doc/rebqn.html">ReBQN</a>…</p> +<p>Dfns are adjusted in a few ways that make them more useful for general-purpose programming. A BQN block always runs to the last statement, so a block like <code><span class='Brace'>{</span><span class='Function'>Update</span> <span class='Value'>𝕩</span><span class='Separator'>⋄</span><span class='Number'>1</span><span class='Function'>+</span><span class='Value'>x</span><span class='Brace'>}</span></code> won't return early. Tradfns are removed entirely, along with control structures.</p> +<p>BQN's namespaces have a dedicated syntax, are <em>much</em> easier to create than Dyalog namespaces, and have better performance. I use them all the time, and they feel like a natural part of the language.</p> <h3 id="j"><a class="header" href="#j">J</a></h3> <p><em>J is under development again and a moving target. I stopped using it completely shortly after starting work on BQN in 2020, and while I try to keep up to date on language changes, some remarks here might not fit with the experience you'd get starting with J today.</em></p> <p>To me building with J feels like making a tower out of wood and nails by hand: J itself is reliable but I soon don't trust what I'm standing on. J projects start to feel hacky when I have multiple files, locales, or a bit of global state. With BQN I begin to worry about maintainability only when I have enough functions that I can't remember what arguments they expect, and with lexically-scoped variables I simply don't use global state. If you don't reach this scale (in particular, if you use J as a calculator or spreadsheet substitute) you won't feel these concerns, and will have less to gain by moving to BQN. And if you go beyond, you'd need to augment your programs with rigorous documentation and testing in either language.</p> @@ -22,6 +32,8 @@ <p>In BQN it's <code><span class='Value'>•path</span></code>. And usually you don't need it because <code><span class='Function'>•Import</span></code> resolves paths relative to the file containing it.</p> <p>J uses numeric codes; BQN uses mostly names. So J's <code><span class='Number'>1</span><span class='Value'>&o.</span></code> is BQN's <code><span class='Value'>•math.</span><span class='Function'>Sin</span></code>, and <code><span class='Number'>6</span><span class='Function'>!</span><span class='Value'>:</span><span class='Number'>9</span></code> corresponds to BQN's <code><span class='Function'>•MonoTime</span></code>.</p> <p>J uses bytestrings by default, making Unicode handling a significant difficulty (<a href="https://code.jsoftware.com/wiki/Vocabulary/uco">see</a> <code><span class='Value'>u:</span></code>). BQN strings are lists of codepoints, so you don't have to worry about how they're encoded or fight to avoid splitting up UTF-8 bytes that need to go together.</p> +<p>But J has its type advantages as well. I miss complex number support in BQN, as it's an optional extension that we haven't yet implemented. And BQN has a hard rule that only one numeric type is exposed to the programmer, which means high-precision integers and rationals aren't allowed at all for a float-based implementation. I think this rule is worth it because J's implicit type conversion is hard to predict and an unexpected numeric type can cause sporadic or subtle program errors.</p> +<p>BQN uses a modifier <code><span class='Modifier2'>⟜</span></code> for J's hook, adding <code><span class='Modifier2'>⊸</span></code> for a reversed version (which I use nearly twice as often). This frees up the 2-train, which is made equivalent to Atop (<code><span class='Modifier2'>∘</span></code>). It's the system Roger Hui came to advocate, since he argued in favor of a hook conjunction <a href="https://code.jsoftware.com/wiki/Essays/Hook_Conjunction%3F">here</a> and made 2-train an Atop when he brought it to Dyalog APL. As an example, the J hook <code><span class='Paren'>(</span><span class='Comment'>#~0&<:)</span></code> to remove negative numbers becomes <code><span class='Number'>0</span><span class='Modifier2'>⊸</span><span class='Function'>≤</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code> in BQN.</p> <p>J locales are not first-class values, and BQN namespaces are. I think BQN's namespaces are a lot more convenient to construct, although it is lacking an inheritance mechanism (but J's path system can become confusing quickly). More importantly, BQN namespaces (and closures) are garbage collected. J locales leak unless manually freed by the programmer. More generally, J has no mutable data at all, and to simulate it properly you'd have to write your own tracing garbage collection as the J interpreter doesn't have any. I discussed this issue some in <a href="http://www.jsoftware.com/pipermail/programming/2021-April/058006.html">this J forum thread</a>.</p> <p>In J, each function has a built-in rank attribute: for example the ranks of <code><span class='Function'>+</span></code> are <code><span class='Number'>0</span> <span class='Number'>0</span> <span class='Number'>0</span></code>. This rank is accessed by the "close" compositions <code><span class='String'>@</span></code>, <code><span class='Value'>&</span></code>, and <code><span class='Value'>&.</span></code>. Choosing the shorter form for the close compositions—for example <code><span class='String'>@</span></code> rather than <code><span class='String'>@</span><span class='Value'>:</span></code>—is often considered a mistake within the J community. And function ranks are unreliable: consider that the ranks of <code><span class='Value'>]</span><span class='String'>@</span><span class='Value'>:</span><span class='Function'>+</span></code>, a function that behaves just like <code><span class='Function'>+</span></code>, are <code><span class='Modifier2'>_</span> <span class='Modifier2'>_</span> <span class='Modifier2'>_</span></code>. In BQN there aren't any close compositions at all, and no function ranks. J's <code><span class='Value'>&.</span><span class='Function'>></span></code> is simply <code><span class='Modifier'>¨</span></code>, and other close compositions, in my opinion, just aren't needed.</p> <p>Gerunds are J's answer to BQN's first-class functions. For example J's <code><span class='Paren'>(</span><span class='Function'>+</span><span class='Value'>&</span><span class='Number'>3</span><span class='Paren'>)</span><span class='Modifier'>`</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Value'>&*</span><span class='Paren'>)</span><span class='String'>@</span><span class='Value'>.</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Value'>&</span><span class='Function'>|</span><span class='Paren'>)</span></code> would be written <code><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>|</span><span class='Modifier2'>◶</span><span class='Bracket'>⟨</span><span class='Function'>+</span><span class='Modifier2'>⟜</span><span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>×</span><span class='Bracket'>⟩</span></code> with a list of functions. I think lists of functions are a big improvement, since there's no need to convert between gerund and function, and no worries about arrays that just happen to be valid gerunds (worried about losing the ability to construct gerunds? Constructing tacit functions in BQN is much easier). The usability gap widens because passing J functions around either as values or gerunds has presents some highly idiosyncratic challenges, discussed below.</p> |
