aboutsummaryrefslogtreecommitdiff
path: root/docs/commentary
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2022-02-09 22:34:36 -0500
committerMarshall Lochbaum <mwlochbaum@gmail.com>2022-02-09 22:34:36 -0500
commit32b4eb2dd8fbc61b9f0df38ee4b24e468ab3e6de (patch)
treeb7d32e9afda5f2bb85de13f4ac8807a8cf410796 /docs/commentary
parent8b46394437ed6dbdcb75a7cf727deadd2ca9e101 (diff)
The problems keep piling up
Diffstat (limited to 'docs/commentary')
-rw-r--r--docs/commentary/problems.html11
1 files changed, 9 insertions, 2 deletions
diff --git a/docs/commentary/problems.html b/docs/commentary/problems.html
index f5a9983b..2e69419e 100644
--- a/docs/commentary/problems.html
+++ b/docs/commentary/problems.html
@@ -47,18 +47,24 @@
<p>It's an awkward inconsistency. Prefixes and Suffixes have to have a nested result, but Windows doesn't have to be flat; it's just that making it nested ignores the fact that it does have an array structure.</p>
<h3 id="converting-a-function-expression-to-a-subject-is-tricky"><a class="header" href="#converting-a-function-expression-to-a-subject-is-tricky">Converting a function expression to a subject is tricky</a></h3>
<p>You can name it, you can write <code><span class='Function'>βŠ‘</span><span class='Bracket'>⟨</span><span class='Function'>Expr</span><span class='Bracket'>⟩</span></code> or <code><span class='Paren'>(</span><span class='Function'>Expr</span><span class='Paren'>)</span><span class='Modifier'>Λ™</span><span class='Number'>0</span></code>, and if it doesn't use special names you can write <code><span class='Brace'>{</span><span class='Function'>Expr</span><span class='Brace'>}</span></code>. All of these are at least a little awkward in reasonable cases. Should there be a dedicated syntax? Note that going the other way, from subject to function, isn't too bad: the modifier <code><span class='Brace'>{</span><span class='Function'>𝔽</span><span class='Brace'>}</span></code> does it, as does <code><span class='Modifier2'>β—‹</span><span class='Function'>⊒</span></code>.</p>
+<h3 id="cant-reduce-or-scan-over-arrays-jointly"><a class="header" href="#cant-reduce-or-scan-over-arrays-jointly">Can't Reduce or Scan over arrays jointly</a></h3>
+<p>Each allows you to move along two arrays simultaneously (sure, three isn't good, but you can usually split into two Each-ed functions). Reduce and Scan are stuck with one, so you might need to pass in a list of tuples. Scan also encourages you to pack a few values into the result, leaving you the same annoying structure. A nested-transpose primitive, similar to <code><span class='Function'>&lt;</span><span class='Modifier'>˘</span><span class='Function'>⍉&gt;</span></code>, would help a lot.</p>
<h3 id="axis-ordering-is-big-endian"><a class="header" href="#axis-ordering-is-big-endian">Axis ordering is big-endian</a></h3>
<p>The most natural ordering for polynomial coefficients and base representations is little-endian, because it aligns element <code><span class='Value'>i</span></code> of the list with power <code><span class='Value'>i</span></code> of the argument or base. It also allows a forward scan instead of a reverse one. Array axes go the other way. However, there are advantages to this ordering as well. For example, it's common to act only on the first few axes, so having them at the beginning of the array is good (<code><span class='Function'>β‰ </span><span class='Value'>a</span> <span class='Gets'>←→</span> <span class='Function'>βŠ‘</span><span class='Modifier2'>∘</span><span class='Function'>β‰’</span><span class='Value'>a</span></code>).</p>
<h3 id="inverse-is-not-fully-specified"><a class="header" href="#inverse-is-not-fully-specified">Inverse is not fully specified</a></h3>
<p>So it seems a bit strange to rely on it for core language features like <code><span class='Function'>/</span><span class='Modifier'>⁼</span></code> (well, that one in particular has been specified, and extended even). On the other hand, this is a good fit for <code><span class='Function'>⋆</span><span class='Modifier'>⁼</span></code> since we are taking an arbitrary branch of a complex function that has many of them. I'm pretty sure it's impossible to solve the issue as stated but it might be possible to move to less hazardous constructs. Structural Under is a start.</p>
<h3 id="choose-and-repeat-have-order-swapped"><a class="header" href="#choose-and-repeat-have-order-swapped">Choose and Repeat have order swapped</a></h3>
<p>In Choose, the selector goes on the left; in Repeat, the count goes on the right. Could be a strength in some contexts, since you can change Repeat-as-If to Choose if you don't like the ordering, but maybe a language that forces the programmer to make semantic decisions for syntactic reasons is not providing the greatest of services.</p>
+<h3 id="have-to-enclose-scan-initial-element"><a class="header" href="#have-to-enclose-scan-initial-element">Have to enclose Scan initial element</a></h3>
+<p>The most common case for Scan is of course applying to a list. Here there can only be one element, but it has to go in a unit array to keep Scan general. The reductions dodge this by leaving out the APL2 style, and Scan hits it dead on.</p>
<h3 id="cant-mix-define-and-modify-in-multiple-assignment"><a class="header" href="#cant-mix-define-and-modify-in-multiple-assignment">Can't mix define and modify in multiple assignment</a></h3>
<p>Say <code><span class='Value'>a</span></code> is a pair and <code><span class='Value'>h</span></code> isn't defined yet; how would you set <code><span class='Value'>h</span></code> to the first element of <code><span class='Value'>a</span></code> and change <code><span class='Value'>a</span></code> to be just the second? <code><span class='Value'>h</span><span class='Ligature'>β€Ώ</span><span class='Value'>a</span><span class='Gets'>↩</span><span class='Value'>a</span></code> doesn't work because <code><span class='Value'>h</span></code> isn't defined, so the best I have is <code><span class='Value'>h</span><span class='Gets'>←</span><span class='String'>@</span><span class='Separator'>β‹„</span><span class='Value'>h</span><span class='Ligature'>β€Ώ</span><span class='Value'>a</span><span class='Gets'>↩</span><span class='Value'>a</span></code>. A heavier assignment syntax wouldn't break down; BQN could allow <code><span class='Bracket'>⟨</span><span class='Value'>h</span><span class='Gets'>←</span><span class='Separator'>,</span><span class='Value'>a</span><span class='Bracket'>⟩</span><span class='Gets'>↩</span><span class='Value'>a</span></code> but I don't think this merits special syntax.</p>
<h3 id="tolerant-comparison"><a class="header" href="#tolerant-comparison">Tolerant comparison</a></h3>
<p>APL has it and BQN doesn't; after some experience it seems this causes few problems, and the extra effort required for the algorithms that do need it is negligible (anyway, it's better to be aware when your code relies on imprecise equality). APL and J also tolerate inexact indices and lengths, which is also something that could be supported.</p>
<h3 id="named-modifiers-use-way-more-space-than-primitive-ones"><a class="header" href="#named-modifiers-use-way-more-space-than-primitive-ones">Named modifiers use way more space than primitive ones</a></h3>
<p><code><span class='Function'>F</span> <span class='Modifier2'>_m_</span> <span class='Function'>G</span></code> versus <code><span class='Function'>F</span><span class='Modifier2'>∘</span><span class='Function'>G</span></code>: the syntax is the same but these don't feel the same at all. This is the worst case, as with primitive operands, <code><span class='Function'>+</span><span class='Modifier2'>_m_</span><span class='Function'>÷</span></code> isn't as far from <code><span class='Function'>+</span><span class='Modifier2'>∘</span><span class='Function'>÷</span></code>. It means a style-conscious programmer has to adjust the way they write code depending on whether things are named, and makes named modifiers feel less integrated into the language. A mix of named modifiers with primitive modifiers or trains can also look inconsistent.</p>
+<h3 id="return-value-prevents-optimization"><a class="header" href="#return-value-prevents-optimization">Return value prevents optimization</a></h3>
+<p>Run something like <code><span class='Value'>a</span><span class='Gets'>←</span><span class='Function'>↕</span><span class='Number'>1e6</span> <span class='Separator'>β‹„</span> <span class='Brace'>{</span><span class='Value'>a</span><span class='Function'>-</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>𝕩</span><span class='Modifier2'>⊸</span><span class='Function'>βŠ‘</span><span class='Paren'>)</span><span class='Gets'>↩</span><span class='Brace'>}</span><span class='Modifier'>Β¨</span><span class='Function'>↕</span><span class='Number'>100</span></code> and you'll get poor performance in current CBQN. This is because <code><span class='Value'>a</span></code> is part of the function result to be used by <code><span class='Modifier'>Β¨</span></code>, creating a reference and preventing in-place updates. The function needs to return something else, with <code><span class='Separator'>β‹„</span><span class='String'>@</span></code> at the end maybe. Various strategies could fix this by tracking whether the result will be needed.</p>
<h3 id="cant-always-transfer-ambivalence-in-tacit-code"><a class="header" href="#cant-always-transfer-ambivalence-in-tacit-code">Can't always transfer ambivalence in tacit code</a></h3>
<p>For example, there's no tacit equivalent of the old APL (NARS) <code><span class='Modifier2'>∘</span></code>, which in explicit BQN is simply <code><span class='Brace'>{</span><span class='Value'>𝕨</span><span class='Function'>𝔽𝔾</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>. Similarly, <code><span class='Brace'>{</span><span class='Paren'>(</span><span class='Function'>𝔽</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code> is missing. The contrast with Atop and Over, which work very smoothly, can be jarring and make it harder to get an intuition for what the code is doing.</p>
<h3 id="index-of-privileges-the-first-match"><a class="header" href="#index-of-privileges-the-first-match">Index Of privileges the first match</a></h3>
@@ -121,12 +127,13 @@
<p>Scan moves along the array so that it uses results as left arguments, which is opposite to the usual right-to-left order of evaluation. But I think this is still better than scanning the array in reverse. You can always use Swap on the operand, or recover the APL scan ordering by doing a Reduce-Each on Prefixes.</p>
<h3 id="bins-is-inconsistent-with-index-of"><a class="header" href="#bins-is-inconsistent-with-index-of">Bins is inconsistent with Index of</a></h3>
<p>In Dyalog APL, Interval Index is identical to Index Of if the left argument has no duplicate cells and every right argument cell intolerantly matches a left argument cell. In BQN they're off by oneβ€”Bins is one larger. But all the caveats for the Dyalog relation indicate this might not be so fundamental.</p>
+<h3 id="empty-left-argument-to-select"><a class="header" href="#empty-left-argument-to-select">Empty left argument to Select</a></h3>
+<p>Select chooses whether <code><span class='Value'>𝕨</span></code> maps to axes of <code><span class='Value'>𝕩</span></code> or selects from the first axis based only on its depth. An empty array has depth 1, so it selects no major cells. However, it could also select from no axes (a no-op) and in some contexts the other behavior would be surprising.</p>
+<p>There's a similar problem with <code><span class='Bracket'>⟨⟩</span></code> as a left argument to <code><span class='Function'>βŠ‘</span></code>: it could be a list of no indices, or a length-0 index. Currently it's treated as an index, causing errors when <code><span class='Value'>𝕨</span></code> is a variable-length list of indices. This could be mostly fixed with backwards compatibility by choosing the other way when <code><span class='Value'>𝕩</span></code> has nonzero rank.</p>
<h3 id="special-names-other-than-𝕣-cant-be-written-as-modifiers"><a class="header" href="#special-names-other-than-𝕣-cant-be-written-as-modifiers">Special names other than 𝕣 can't be written as modifiers</a></h3>
<p>I decided that it was better to allow <code><span class='Value'>𝕨</span><span class='Modifier2'>_m_</span><span class='Value'>𝕩</span></code> to work with no spaces than to allow <code><span class='Modifier2'>_</span><span class='Value'>𝕩</span></code> to be a modifier, and this rule also helps keep tokenization simple. But to apply <code><span class='Value'>𝕩</span></code> as a modifier you have to give it a different name. Could actually be a good thing in that it encourages you to stick to functions, as they're nicer in lots of other ways.</p>
<h3 id="exact-result-of-power-is-unspecified"><a class="header" href="#exact-result-of-power-is-unspecified">Exact result of Power is unspecified</a></h3>
<p>The other arithmetic functions round to nearest, and compound functions such as <code><span class='Value'>βŠ₯</span></code> have been removed. But Power makes no guarantees, and the result could change over time based on different special code. Dyadic logarithm is similar, but expected because of its inverse status.</p>
-<h3 id="empty-left-argument-to-select"><a class="header" href="#empty-left-argument-to-select">Empty left argument to Select</a></h3>
-<p>Select chooses whether the left argument maps to right argument axes or selects from the first axis only based on its depth. Without prototypes an empty array has depth 1, so it selects no major cells. However, it could also select from no axes (a no-op) and in some contexts the other behavior would be surprising.</p>
<h3 id="unclear-primitive-names"><a class="header" href="#unclear-primitive-names">Unclear primitive names</a></h3>
<p>Blanket issue for names that I don't find informative: &quot;Solo&quot;, &quot;Bins&quot;, &quot;Find&quot;, and &quot;Group&quot;.</p>
<h3 id="tacit-exports-can-leak-data"><a class="header" href="#tacit-exports-can-leak-data">Tacit exports can leak data</a></h3>