Marshall Lochbaum
List of changes I expect to make before fixing version 1.0 of the BQN core language specification, as well as features in the spec not yet implemented. The core language is everything but system functions, so these are out of scope.
All version 1.0 features are finished! Advanced namespace features have been left for 1.1.
Top Answer
Marshall Lochbaum
### (DONE) Inverse headers
Specifying how Undo should apply to blocks, for example `{𝕊⁼𝕩:𝕩-1; 𝕩+1}`.
Answer #2
Marshall Lochbaum
### (DONE) High-rank array notation
See [here](https://mlochbaum.github.io/BQN/commentary/problems.html#high-rank-array-notation). `[]` is a literal notation for `>⟨⟩`, and that's it. So the following block gives two representations of the same shape `2‿3` matrix. This notation allows destructuring arrays with rank more than 1, which isn't possible without it.
```bqn
[2‿3‿4 , 5‿3‿1] # One line
[
⟨2,3,4⟩
⟨5,3,1⟩
]
```
It means that the bytecode now needs to include `>` as a basic operation. However, header destructuring already requires `≡` which makes this seem less weird.
Answer #3
Marshall Lochbaum
### (1.1?) Mutable namespace fields
Sometimes it's useful to modify a field of a namespace from the outside, and the obvious syntax for this is `ns.field↩value`. dzaima/BQN supports this for all namespaces but I think it should be disabled by default, meaning that it should have to be enabled, either for the namespace as a whole or specific variables. Per-variable, replacing `⇐` with `↩⇐` to indicate mutable exports works but isn't nice to read.
Since it's not that hard to define a setter `SetVar⇐{var↩𝕩}` this isn't terribly important, and I'd be fine leaving it for version 1.1.
Answer #4
Marshall Lochbaum
### (1.1?) Default values in namespace destructuring
If `ns` is a namespace, `⟨f,a‿b⇐g,h⟩←ns` requires that it has all the fields `f`, `g`, and `h`. But you might want to accept a namespace that doesn't have some of them and replace missing values with a default. A possible syntax for this is `⟨f,a‿b⇐g?"ab",h?100⟩←ns`. Very uncertain.
Answer #5
Marshall Lochbaum
### (DONE) Rank-tolerant Join (`∾`)
Described [here](https://chat.stackexchange.com/transcript/52405?m=55965971#55965971). I'm tired of having Join fail when the argument contains some lists and some units but haven't gotten around to implementing this in the spec and runtime.
Answer #6
Marshall Lochbaum
### (DONE) Predicates
The way they work is that `?` in a block functions as a separator, so it can be placed after any expression. After the expression finishes, it checks the result, which must be boolean. If it's `0`, it stops the current body and tries the next one instead.
This allows some nice syntax like `{cond? ifTrue; ifFalse}` for an if-else structure, where the three components can all be any number of expressions. Values defined in `cond` can be used in `ifTrue`, but not `ifFalse`, since it has its own scope.
Answer #7
Marshall Lochbaum
### (DONE) Roles and immediateness with multiple headers?
The system now is basically that block type is the simplest consistent with all bodies, and the only possible error is if a header conflicts with another header or special names. Distinctions in capabilities between arguments and inputs have been removed. Following discussion is based on previous rules:
The specification says right now that the kind of block (type and immediateness) is determined by what special names appear across all headers. When I added these to the compiler I questioned this and used a different rule, that each body determines its own properties and different bodies have to agree. This turns out to be too strict since not allowing things like `{a+b;𝕨+b}` (left half would be a subject) is a significant annoyance. I still think the spec as written is slightly too lenient and am considering various possibilities in between.
Probably complicated by predicates `?`, which would mean that immediate blocks with multiple bodies make sense. Current spec says a block containing `;` takes arguments.
Not exactly the same thing but I also now think immediate modifiers should probably allow multiple cases, since allowing them seems less complicated than disallowing them.
Answer #8
Marshall Lochbaum
### (REMOVED) 2-modifier partial application
Removed from the spec; never supported in the compiler. dzaima/BQN has it but only for binding a right operand (matching Dyalog APL). These are certainly useful, but I've started thinking that the cost to adding more expression syntax is significant, particularly in how it makes the language less approachable. It's fairly easy to write out a block that binds the operand, and rare enough that syntax for partial application might not be justified.
Answer #9
Marshall Lochbaum
### (DONE) Structural Under
Was missing support for cases that combine arrays together, such as `∾`. I've implemented them, and decided to keep them in the spec. Despite the implementation difficulty, the utility seems worth it.
Answer #10
Marshall Lochbaum
### (DONE) Assignment placeholder
When destructuring it sometimes happens that part of the structure isn't needed. The name `·` (also considered was `_`) now indicates an ignored value to help express intent here. In contrast, naming things that don't even do anything would be pretty annoying.
Answer #11
Marshall Lochbaum
### (DONE) Enlist/Pair (`⋈`)
New primitive, equivalent to `≍○<`. This is a very common pattern, and a natural thing to want to do: given that `≍` is `>∘⋈`, it's hard to say which of the two is more fundamental.
Answer #12
Marshall Lochbaum
#### (DONE) One-argument modified assignment
Apply a one-argument function to a variable in-place. Yiyus suggests `var Fn↩`, with no right-hand side, for the syntax here, which seems likely to be the best option.
Answer #13
Marshall Lochbaum
### (REMOVED) Returns
Constructs like `Fn→` to return from function `Fn` have never been implemented anywhere and are now removed from the spec. They're difficult for the runtime to implement. And they break some guarantees because a body can now return a value even if its lines haven't all been evaluated. In particular handling of `𝕨` is complicated because it's no longer safe to assume that a function where `𝕨` can't be `·` on one line will error if called with one argument.
It seems predicates (`?`) cover a lot of places where returns would be wanted. The thing you still need them for is a multi-level break, which is frequently left out even in the imperative world. And they're useful for shortcutting a mapping or iteration primitive. Because of the complexity I'm considering leaving these for 1.1 or dropping them entirely.