Skip to content

Commit

Permalink
Early returns were withdrawn, and •math.Sum exists now
Browse files Browse the repository at this point in the history
  • Loading branch information
mlochbaum committed Dec 6, 2023
1 parent 82b15a3 commit 1de7c5d
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 10 deletions.
10 changes: 4 additions & 6 deletions commentary/problems.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ You can name it, you can write `⊑⟨Expr⟩` or `(Expr)˙0`, and if it doesn't
### Can't Reduce or Scan over arrays jointly
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 `<˘⍉>`, would help a lot.

### Can't return from inner functions
This is an issue with using functions as control flow. For example, when looping through an array with Each, you can't decide to exit early. In a curly-brace language you would just use a for loop and a return. In BQN, the planned feature was a block return like `label←` to jump out of a block with header name `label`. This was never implemented anywhere. Predicates cover some of the simpler use cases, and when they were added I decided early returns weren't worth the added complexity and dropped the idea.

### Axis ordering is big-endian
The most natural ordering for polynomial coefficients and base representations is little-endian, because it aligns element `i` of the list with power `i` 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 (`≠a ←→ ⊑∘≢a`).

Expand Down Expand Up @@ -141,7 +144,7 @@ Only `⍋⍒` use array ordering rather than just array equality or numeric orde
Evaluating a derived function does a lot of work that often can't be connected with any particular source location. This is why stack traces don't dig into tacit functions, for now at least. For the interactive side of debugging, `•Show` is so powerful in tacit code that I'm not sure this is even an issue, but it's still worth keeping in mind if BQN adds a more traditional debugger. And it's troublesome for implementers, who tend to rely on stepping through opcodes.

### No access to fast high-precision sum
Fold has a specific order of application, which must be used for `` +` ``. 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. Absent this feature it will probably be provided with `•math.Sum`.
Fold has a specific order of application, which must be used for ``. But other orders can be both faster and more precise (in typical cases) by enabling greater parallelism. This is exposed by `•math.Sum`, but arithmetic in a system function is ugly. 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.

### No one right way to check if a value is an array
The mathematical approach is `0<≡𝕩`, which can be slow without runtime support, while the efficient approach is `0=•Type𝕩`, which is ugly and uses a system function for something that has nothing at all to do with the system. These are minor flaws, but programmers shouldn't have to hesitate about which one they want to use.
Expand Down Expand Up @@ -254,11 +257,6 @@ BQN bounced between these some at first; eventually I decided it really needed t
### "Modifier" and "composition" terminology
1-modifiers and 2-modifiers used to be called "modifiers" and "compositions", respectively, and sometimes "operators" collectively. The new names are much better, although they do leave a disconnect between the names for modifiers, and those for their inputs—"operands".

### Can't return from inner functions
Fixed by adding block returns such as `label←` to jump out of a block with header name `label`. Hopefully these don't cause too many new problems.

This was an issue with using functions as control flow. For example, when looping through an array with Each, you can't decide to exit early. In a curly-brace language you would just use a for loop and a return. In BQN, we need… longjmp? Maybe not as crazy as it sounds, and potentially worth it in exchange for replacing control structures.

### Ambivalent explicit functions
Fixed with multiple bodies: if there are two bodies with no headers such as `{2×𝕩;𝕨-𝕩}`, they are the monadic and dyadic case.

Expand Down
7 changes: 3 additions & 4 deletions docs/commentary/problems.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ <h3 id="converting-a-function-expression-to-a-subject-is-tricky"><a class="heade
<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="cant-return-from-inner-functions"><a class="header" href="#cant-return-from-inner-functions">Can't return from inner functions</a></h3>
<p>This is an issue with using functions as control flow. For example, when looping through an array with Each, you can't decide to exit early. In a curly-brace language you would just use a for loop and a return. In BQN, the planned feature was a block return like <code><span class='Value'>label</span><span class='Gets'></span></code> to jump out of a block with header name <code><span class='Value'>label</span></code>. This was never implemented anywhere. Predicates cover some of the simpler use cases, and when they were added I decided early returns weren't worth the added complexity and dropped the idea.</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>
Expand Down Expand Up @@ -95,7 +97,7 @@ <h3 id="cant-access-array-ordering-directly"><a class="header" href="#cant-acces
<h3 id="tacit-evaluation-is-opaque"><a class="header" href="#tacit-evaluation-is-opaque">Tacit evaluation is opaque</a></h3>
<p>Evaluating a derived function does a lot of work that often can't be connected with any particular source location. This is why stack traces don't dig into tacit functions, for now at least. For the interactive side of debugging, <code><span class='Function'>•Show</span></code> is so powerful in tacit code that I'm not sure this is even an issue, but it's still worth keeping in mind if BQN adds a more traditional debugger. And it's troublesome for implementers, who tend to rely on stepping through opcodes.</p>
<h3 id="no-access-to-fast-high-precision-sum"><a class="header" href="#no-access-to-fast-high-precision-sum">No access to fast high-precision sum</a></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. Absent this feature it will probably be provided with <code><span class='Value'>•math.</span><span class='Function'>Sum</span></code>.</p>
<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. This is exposed by <code><span class='Value'>•math.</span><span class='Function'>Sum</span></code>, but arithmetic in a system function is ugly. 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="no-one-right-way-to-check-if-a-value-is-an-array"><a class="header" href="#no-one-right-way-to-check-if-a-value-is-an-array">No one right way to check if a value is an array</a></h3>
<p>The mathematical approach is <code><span class='Number'>0</span><span class='Function'>&lt;≡</span><span class='Value'>𝕩</span></code>, which can be slow without runtime support, while the efficient approach is <code><span class='Number'>0</span><span class='Function'>=•Type</span><span class='Value'>𝕩</span></code>, which is ugly and uses a system function for something that has nothing at all to do with the system. These are minor flaws, but programmers shouldn't have to hesitate about which one they want to use.</p>
<h3 id="tacit-code-cant-build-lists-easily"><a class="header" href="#tacit-code-cant-build-lists-easily">Tacit code can't build lists easily</a></h3>
Expand Down Expand Up @@ -170,9 +172,6 @@ <h3 id="array-reductions-are-annoying"><a class="header" href="#array-reductions
<p>BQN bounced between these some at first; eventually I decided it really needed two, with <code><span class='Function'>𝔽</span><span class='Modifier'>˝</span></code> equivalent to <code><span class='Function'>𝔽</span><span class='Modifier'>´</span><span class='Function'>&lt;</span><span class='Modifier'>˘</span></code>. The last requires two symbols, but they can always be used together as a unit, so I think this is no longer annoying.</p>
<h3 id="modifier-and-composition-terminology"><a class="header" href="#modifier-and-composition-terminology">&quot;Modifier&quot; and &quot;composition&quot; terminology</a></h3>
<p>1-modifiers and 2-modifiers used to be called &quot;modifiers&quot; and &quot;compositions&quot;, respectively, and sometimes &quot;operators&quot; collectively. The new names are much better, although they do leave a disconnect between the names for modifiers, and those for their inputs—&quot;operands&quot;.</p>
<h3 id="cant-return-from-inner-functions"><a class="header" href="#cant-return-from-inner-functions">Can't return from inner functions</a></h3>
<p>Fixed by adding block returns such as <code><span class='Value'>label</span><span class='Gets'></span></code> to jump out of a block with header name <code><span class='Value'>label</span></code>. Hopefully these don't cause too many new problems.</p>
<p>This was an issue with using functions as control flow. For example, when looping through an array with Each, you can't decide to exit early. In a curly-brace language you would just use a for loop and a return. In BQN, we need… longjmp? Maybe not as crazy as it sounds, and potentially worth it in exchange for replacing control structures.</p>
<h3 id="ambivalent-explicit-functions"><a class="header" href="#ambivalent-explicit-functions">Ambivalent explicit functions</a></h3>
<p>Fixed with multiple bodies: if there are two bodies with no headers such as <code><span class='Brace'>{</span><span class='Number'>2</span><span class='Function'>×</span><span class='Value'>𝕩</span><span class='Head'>;</span><span class='Value'>𝕨</span><span class='Function'>-</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>, they are the monadic and dyadic case.</p>
<h3 id="how-to-choose-a-partitioning-function"><a class="header" href="#how-to-choose-a-partitioning-function">How to choose a partitioning function?</a></h3>
Expand Down

0 comments on commit 1de7c5d

Please sign in to comment.