diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2020-08-19 14:39:38 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2020-08-19 14:39:38 -0400 |
| commit | e4db91ec2c8a34dbdaa635d6789c5ecc68e34954 (patch) | |
| tree | c7db4498f938d1f771aac2928b68d7d843cc26d2 /docs | |
| parent | e22481939afecb6ccfc31c2da01bee59dc8e6667 (diff) | |
Enhance problems
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/problems.html | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/docs/problems.html b/docs/problems.html index 595ed18d..a15a0e17 100644 --- a/docs/problems.html +++ b/docs/problems.html @@ -5,11 +5,10 @@ <p>I've omitted problems that are obviously addressed by speculated extensions. Of course adding A fixes the problem "doesn't have A". Problems that only exist in reference to some existing convention (e.g. unfamiliarity to APLers) are also left out, unless the convention manifests technically (Unicode support).</p> <h3 id="empty-arrays-lose-type-information">Empty arrays lose type information</h3> <p>A pretty fundamental problem with dynamically-typed array languages. Prototypes are intended to solve it, but they don't really. It doesn't help that the notion of type is fluid: elements of an array in one moment can be axis lengths in the next; did the numeric value go from not being type information to being type information? Inferred type might help here, particularly the ability of one part of the program to ask another part for type information during compilation. But that needs to be specified if programmers are going to rely on it, which sounds difficult.</p> -<h3 id="control-flow-with-function-selection-has-awkward-syntax">Control flow with function selection has awkward syntax</h3> -<p>At the moment BQN has no control structures, instead preferring function recursion, iteration, and selection. Selection is awkward because the result of selecting from a list of functions is a subject syntactically. It also often doesn't need an argument, since it can refer to values from the containing function because of lexical scoping. There should possibly be a function that takes a function argument and invokes it, possible with an empty list as a dummy left argument. Somewhat like the modifier <code><span class='Brace'>{</span><span class='Function'>π½</span><span class='Brace'>}</span></code>.</p> -<p><em>Potentially solved by multiple headers, blocks, and block returns. Needs reevaluation later.</em></p> <h3 id="incoherent-monad-dyad-builtin-pairs">Incoherent monad-dyad builtin pairs</h3> <p>BQN inherits the functions <code><span class='Function'>+Γββ|</span></code>, and adds the functions <code><span class='Function'>β§β¨<>β β‘β’ββ·</span></code>, that are only paired for their glyphs and not for any other reason (that is, both function valences match the symbol but they don't match with each other). I find there are just not enough good glyphs to separate all of these out, but I'm sure the pairings could be improved.</p> +<h3 id="control-flow-substitutes-have-awkward-syntax">Control flow substitutes have awkward syntax</h3> +<p>At the moment BQN has no control structures, instead preferring operators, function recursion, and headers. When working with pure functions, these can be better than control structures. For more imperative programming they're a lot worse. Given that blocks without headers also end up with an unexpected type if you don't use the inputs, it's safe to say BQN isn't great for imperative programming overall. But that's a big loss, and it's very much worth fixing if it can be done with something like a single control structure that conditionally or repeatedly executes an immediate block.</p> <h3 id="glyphs-are-hard-to-type">Glyphs are hard to type</h3> <p>There's been a lot of work done on this. Still there, still a problem. On the other hand, glyphs are easy to read, and write by hand!</p> <h3 id="tacit-and-one-line-functions-are-hard-to-debug">Tacit and one-line functions are hard to debug</h3> @@ -20,8 +19,12 @@ <p>There are a lot of standard functions and I don't want to use separate primitives or a menu-style primitive like APL Circle for them. You can define all the functions eventually if you use complex exponential and take real and imaginary parts and inverses, but this doesn't sound well-suited for implementation. And there should be a math library that gives you the standard functions with normal names, but how will it be implemented?</p> <h3 id="right-to-left-multi-line-functions-go-upwards">Right-to-left multi-line functions go upwards</h3> <p>If you include multiple multi-line functions in what would otherwise be a one-liner, the flow in each function goes top to bottom but the functions are executed bottom to top. I think the fix here is to just say give your functions names and don't do this.</p> +<h3 id="hard-to-search-part-of-an-array-or-in-a-different-order">Hard to search part of an array or in a different order</h3> +<p>This includes index-of-last, and searching starting at a particular index, when the desired result indices are to the array to be seached <em>before</em> it is modified. Given indices <code><span class='Value'>i</span></code> into an array <code><span class='Value'>π¨</span></code> (for example <code><span class='Function'>β½ββ </span><span class='Value'>π¨</span></code> or <code><span class='Value'>a</span><span class='Function'>+β</span><span class='Value'>b</span></code>), this section can be searched with <code><span class='Paren'>(</span><span class='Value'>i</span><span class='Function'>βΎβ </span><span class='Value'>π¨</span><span class='Paren'>)</span><span class='Function'>β</span><span class='Modifier'>Λ</span><span class='Paren'>(</span><span class='Value'>i</span><span class='Function'>β</span><span class='Value'>π¨</span><span class='Paren'>)</span><span class='Function'>β</span><span class='Value'>π©</span></code>. But this is clunky and difficult for the implementation to optimize.</p> <h3 id="subtraction-division-and-span-are-backwards">Subtraction, division, and span are backwards</h3> <p>The left argument feels much more like the primary one in these cases (indeed, this matches the typical left-to-right ordering of binary operators in mathematics). Not really fixable; too much precedent.</p> +<h3 id="nothing--interacts-strangely-with-before-and-after">Nothing (<code><span class='Nothing'>Β·</span></code>) interacts strangely with Before and After</h3> +<p>Since <code><span class='Value'>π¨</span><span class='Function'>F</span><span class='Modifier2'>βΈ</span><span class='Function'>G</span><span class='Value'>π©</span></code> is <code><span class='Paren'>(</span><span class='Function'>F</span><span class='Value'>π¨</span><span class='Paren'>)</span><span class='Function'>G</span><span class='Value'>π©</span></code> and <code><span class='Value'>π¨</span><span class='Function'>F</span><span class='Modifier2'>β</span><span class='Function'>G</span><span class='Value'>π©</span></code> is <code><span class='Value'>π¨</span><span class='Function'>F</span> <span class='Function'>G</span><span class='Value'>π©</span></code> in the dyadic case, we might expect these to devolve to <code><span class='Function'>G</span><span class='Value'>π©</span></code> and <code><span class='Function'>F</span> <span class='Function'>G</span><span class='Value'>π©</span></code> when <code><span class='Value'>π¨</span></code> is not present. Not so: instead <code><span class='Value'>π©</span></code> is substituted for the missing <code><span class='Value'>π¨</span></code>. And Before and After are also the main places where a programmer might try to use <code><span class='Value'>π¨</span></code> as an operand, which doesn't work either (the right way is the train <code><span class='Value'>π¨</span><span class='Function'>Fβ’</span></code>).</p> <h3 id="cant-access-array-ordering-directly">Can't access array ordering directly</h3> <p>Only <code><span class='Function'>ββ</span></code> use array ordering rather than just array equality or numeric ordering. Getting at the actual ordering to just compare two arrays is more difficult than it should be (but not <em>that</em> difficult: <code><span class='Function'>β₯</span><span class='Modifier2'>βΈ</span><span class='Function'>β</span><span class='Modifier2'>βΎ</span><span class='Function'><</span></code> is TAO <code><span class='Function'>β€</span></code>).</p> <h3 id="syntactic-type-erasure">Syntactic type erasure</h3> @@ -44,44 +47,61 @@ </tr> </tbody> </table> +<h3 id="no-access-to-fast-high-precision-sum">No access to fast high-precision sum</h3> +<p>Fold has a specific order of application, which must be used for <code><span class='Function'>+</span><span class='Modifier'>`</span></code>. But other orders can be both faster and more precise (in typical cases) by enabling greater parallelism. Generally ties into the question of providing precision control for a program: it could be fixed by a flag that enables BQN to optimize as long as the results will be at least as precise (relative to the same program in infinite precision) as the spec.</p> <h3 id="high-rank-array-notation">High-rank array notation</h3> <p>The proposed Dyalog array notation <code><span class='Value'>[]</span></code> for high-rank arrays: it's the same as BQN's lists <code><span class='Bracket'>β¨β©</span></code> except it mixes at the end. This works visually because the bottom levelβrowsβis written with stranding. It also looks okay with BQN strands but clashes with BQN lists. At that point it becomes apparent that specifying whether something is a high-rank array at the top axes is kind of strange: shouldn't it be the lower axes saying to combine with higher ones?</p> <h3 id="poor-font-support-">Poor font support</h3> <p>Characters <code><span class='Function'>β₯βΎ</span><span class='Modifier2'>βββ</span><span class='Modifier'>Λ</span></code> and double-struck letters are either missing from many fonts or drawn strangely.</p> +<h3 id="choose-and-repeat-have-order-swapped">Choose and Repeat have order swapped</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="index-of-privileges-the-first-match">Index Of privileges the first match</h3> <p>It could be more sound to look at all matches, but using just the first one is too convenient. J has an index-of-last function; in BQN you have to reverse the left argument and then do arithmetic: <code><span class='Function'>β </span><span class='Modifier2'>β</span><span class='Function'>β£-</span><span class='Number'>1</span><span class='Function'>+β½</span><span class='Modifier2'>βΈ</span><span class='Function'>β</span></code>.</p> <h3 id="glyphs-that-arent-great">Glyphs that aren't great</h3> <p>Blanket issue for glyphs that need work. Currently I find <code><span class='Function'>β₯βββββ·</span><span class='Modifier'>βΌ</span><span class='Modifier2'>ββ</span></code> to not be particularly good fits for what they describe.</p> +<h3 id="group-doesnt-include-trailing-empty-groups">Group doesn't include trailing empty groups</h3> +<p>But there are workarounds, described in <a href="doc/group.html">its documentation</a>. dzaima has suggested allowing a single extra element in the index argument to specify the result shape. Another possibility is for the result prototype to be specified to allow overtaking.</p> <h3 id="axis-ordering-is-big-endian">Axis ordering is big-endian</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="trains-dont-like-monads">Trains don't like monads</h3> <p>If you have the normal mix of monads and dyads you'll need a lot of parentheses and might end up abusing <code><span class='Modifier2'>β</span></code>. Largely solved with the "nothing" glyph <code><span class='Nothing'>Β·</span></code>, which acts like J's Cap (<code><span class='Value'>[:</span></code>) in a train, but still a minor frustration.</p> <h3 id="inverse-is-not-fully-specified">Inverse is not fully specified</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>. 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="monadic--versus-">Monadic <code><span class='Function'>β</span></code> versus <code><span class='Function'>></span></code></h3> -<p>Both pull out elements and reduce the depth. But they face in opposite directions.</p> -<p>The directions of <code><span class='Function'>ββ</span></code> and so on were mainly chosen to line up with <code><span class='Function'>β</span></code>: the argument that indices apply to (that is, the one that is searched or selected from) corresponds to the open side of the function. I'd probably prefer new glyphs that don't have this sort of directionality, however.</p> <h3 id="converting-a-function-expression-to-a-subject-is-tricky">Converting a function expression to a subject is tricky</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>, 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.</p> -<h3 id="monadic-argument-corresponds-to-left-for--and-">Monadic argument corresponds to left for <code><span class='Function'>/</span></code> and <code><span class='Function'>β</span></code></h3> -<p>Called dyadically, both functions shuffle cells of the right argument around, which is consistent with other selection-type functions. But the monadic case applies to what would be the left argument in the dyadic case.</p> <h3 id="prefixessuffixes-add-depth-and-windows-doesnt">Prefixes/Suffixes add depth and Windows doesn't</h3> <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="at-which-scope-does-a-block-function-belong">At which scope does a block function belong?</h3> +<p>As a general principle, a programmer should make choices in one part of a program that constrain other parts of the program most tightly. This is a weak principle, but often it doesn't conflict with any other preferences and can be followed for free. For example it's usually best to define a variable in the smallest possible scope, so the reader knows it isn't used outside that scope. The same principle applies to blocks, but there is another conflicting principle: placing the block in a broader scope guarantees it won't access the variables in narrower ones. There's no position that will tell the reader, for example, that a function only uses variables local to itself and that it's only used within one particular scope.</p> +<p>This is an issue with any lexically-scoped language; it's unlikely BQN can solve it. On the other hand, I'm surprised I've never seen any discussion of such a universal issue.</p> <h3 id="rankdepth-negative-zero">Rank/Depth negative zero</h3> <p>A positive operand to Rank indicates the cell rank, so positive zero means to act on 0-cells. A negative operand indicates the frame length, so negative zero should act on the entire array. But it can't because it's equal to positive zero. Similar issue with Depth. Positive/negative is not really the right way to encode the frame/cell distinction, but it's convenient. Fortunately β can be used in place of negative zero, but there can still be problems if the rank is computed.</p> <h3 id="must-read-the-body-to-find-explicit-definitions-type">Must read the body to find explicit definition's type</h3> <p>You have to scan for headers or double-struck names (and so does a compiler). A little inelegant, and difficult to describe in BNF.</p> +<h3 id="each-block-body-has-its-own-label">Each block body has its own label</h3> +<p>In a block with multiple bodies, the label (the self-name part of the header) refers to the entire block. However, there's no way to give only one label to the entire block. If you want to consistently use the same internal name, then you may have to write it many times. It's also a weird mismatch, conceptually.</p> +<h3 id="monadic-argument-corresponds-to-left-for--and-">Monadic argument corresponds to left for <code><span class='Function'>/</span></code> and <code><span class='Function'>β</span></code></h3> +<p>Called dyadically, both functions shuffle cells of the right argument around, which is consistent with other selection-type functions. But the monadic case applies to what would be the left argument in the dyadic case.</p> +<h3 id="hard-to-manipulate-the-result-of-a-modifier">Hard to manipulate the result of a modifier</h3> +<p>Trains and compositions make it easy to work with the results of functions, in some sense. The same can't be said for modifiers: for example, in a non-immediate block modifier, the derived function is <code><span class='Function'>π</span></code>, but you can't apply <code><span class='Modifier'>Λ</span></code> to it. This seems to call for modifer trains but people who worked with early J are confident they're not worth it. Or were they just not designed right?</p> +<h3 id="monadic--versus-">Monadic <code><span class='Function'>β</span></code> versus <code><span class='Function'>></span></code></h3> +<p>Both pull out elements and reduce the depth. But they face in opposite directions. However, neither should be thought of as the inverse to <code><span class='Function'><</span></code>: that's <code><span class='Function'><</span><span class='Modifier'>βΌ</span></code>. And <code><span class='Function'>></span></code> can't reduce the depth to 0, so it's pretty different from <code><span class='Function'>β</span></code> or <code><span class='Function'><</span><span class='Modifier'>βΌ</span></code>.</p> +<p>The directions of <code><span class='Function'>ββ</span></code> and so on were mainly chosen to line up with <code><span class='Function'>β</span></code>: the argument that indices apply to (that is, the one that is searched or selected from) corresponds to the open side of the function. I'd probably prefer new glyphs that don't have this sort of directionality, however.</p> <h3 id="cant-take-prefixes-or-suffixes-on-multiple-axes">Can't take Prefixes or Suffixes on multiple axes</h3> <p>This is a natural array operation to do, and results in an array with a joinable structure, but as Prefixes and Suffixes are monadic there's no way to specify the number of axes to use.</p> +<h3 id="modified-assignment-modifies-the-left-secondary-argument">Modified assignment modifies the left (secondary) argument</h3> +<p>So you end up with <code><span class='Modifier'>Λ</span><span class='Gets'>β©</span></code> a lot of the time. For ordinary assignment it's pretty reasonable to say the value is primary, but modified assignment flips this around.</p> <h3 id="andormaxmin-are-all-tangled-up">And/Or/Max/Min are all tangled up</h3> <p>Boolean And (<code><span class='Function'>β§</span></code>) and Or (<code><span class='Function'>β¨</span></code>) are identical to Min (<code><span class='Function'>β</span></code>) and Max (<code><span class='Function'>β</span></code>) when restricted to Boolean arguments, and this would fit nicely with their monadic role as sorting functions: for example <code><span class='Value'>a</span><span class='Function'>β§</span><span class='Value'>b</span> <span class='Gets'>ββ</span> <span class='Function'>ββ§</span><span class='Value'>a</span><span class='Ligature'>βΏ</span><span class='Value'>b</span></code>. Furthermore the pairing of Min with Floor and Max with Ceiling is mnemonic only and not especially natural. The reason I have not used these glyphs for Min and Max, and have instead extended them to the somewhat superfluous <a href="doc/logic.html">arithmetic logical functions</a> is that Min and Max have different <a href="https://aplwiki.com/wiki/Identity_element">identity elements</a> of <code><span class='Number'>β</span></code> and <code><span class='Number'>Β―β</span></code> rather than <code><span class='Number'>1</span></code> and <code><span class='Number'>0</span></code>. Having to code around empty arrays when using <code><span class='Function'>β§</span><span class='Modifier'>Β΄</span></code> would be a fairly big issue.</p> <p>The other drawback of Min (<code><span class='Function'>β§</span></code>) and Max (<code><span class='Function'>β¨</span></code>) is that the symbols are counterintuitive, but I have found a way to remember them: consider the graph of variables <code><span class='Value'>a</span><span class='Gets'>β</span><span class='Value'>x</span></code> and <code><span class='Value'>b</span><span class='Gets'>β</span><span class='Function'>Β¬</span><span class='Value'>x</span></code> for x from 0 to 1: two crossed lines. Now the graph of <code><span class='Value'>a</span><span class='Function'>β§</span><span class='Value'>b</span></code> is a caret shape and <code><span class='Value'>a</span><span class='Function'>β¨</span><span class='Value'>b</span></code> is a vee.</p> <h3 id="acting-on-windows-can-be-awkward">Acting on windows can be awkward</h3> <p>When taking Windows along more than one axis, acting on the resulting array requires the Rank modifier, duplicating either the right argument rank or (negated) left argument length. A nested Windows would only require Each.</p> -<h3 id="group-doesnt-include-trailing-empty-groups">Group doesn't include trailing empty groups</h3> -<p>But there are workarounds, described in <a href="doc/group.html">its documentation</a>. dzaima has suggested allowing a single extra element in the index argument to specify the result shape. Another possibility is for the result prototype to be specified to allow overtaking.</p> +<h3 id="inputs-to-modifiers-are-called-operands">Inputs to modifiers are called operands?</h3> +<p>"Operand" is derived from "operator". "Modificand" would be better if it weren't both made up and hideous.</p> <h3 id="scan-ordering-is-weird">Scan ordering is weird</h3> <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="only-errors-in-functions-can-be-caught">Only errors in functions can be caught</h3> +<p>The operator <code><span class='Modifier2'>β</span></code> allows errors in a function to be caught, but a more natural unit for this is the block (scope, really). However, catching errors shouldn't be common in typical code, in the sense that an application should have only a few instances of <code><span class='Modifier2'>β</span></code>. Ordinary testing and control flow should be preferred instead.</p> <h3 id="bins-is-inconsistent-with-index-of">Bins is inconsistent with Index of</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="exact-result-of-power-is-unspecified">Exact result of Power is unspecified</h3> @@ -90,6 +110,8 @@ <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">Unclear primitive names</h3> <p>Blanket issue for names that I don't find informative: "Solo", "Bins", "Unique Mask", "Find", and "Group".</p> +<h3 id="strands-go-left-to-right">Strands go left to right</h3> +<p>This is the best ordering, since it's consistent with <code><span class='Bracket'>β¨</span><span class='Separator'>β</span><span class='Bracket'>β©</span></code> lists. And code in a strand probably shouldn't have side effects anyway. Still, it's an odd little tack-on to say separators <em>and strands</em> go left to right, and it complicates the implementation a little.</p> <h3 id="should-have-a-rounding-function">Should have a rounding function</h3> <p>There is a standard way to round floatsβto nearest integer, ties to evenβbut it's fairly hard to implement and would have to be specially recognized for performance. It would be nice to have a better way to access this.</p> <h3 id="primitive-name-capitalization">Primitive name capitalization</h3> |
