aboutsummaryrefslogtreecommitdiff
path: root/doc/fill.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/fill.md')
-rw-r--r--doc/fill.md28
1 files changed, 20 insertions, 8 deletions
diff --git a/doc/fill.md b/doc/fill.md
index d330537a..d33c0d85 100644
--- a/doc/fill.md
+++ b/doc/fill.md
@@ -4,19 +4,19 @@
A few array operations need an array element to use when no existing element applies. BQN tries to maintain a "default" element for every array, known as a fill element, for this purpose. If it's known, the fill element is a nested array structure where each atom is either `0` or `' '`. If no fill is known, a function that requests it results in an error.
-Fills are used by [Take](take.md) (`↑`) when a value in `𝕨` is larger than the corresponding length in `𝕩`, by the two [Nudge](shift.md) functions (`»«`) when `𝕩` is non-empty, by [Merge](couple.md) (`>`) when `𝕩` is empty, and by [Reshape](reshape.md) (`β₯Š`) when `𝕨` contains `↑`. Except for these specific cases, the fill value an array has can't affect the program. The result of [Match](match.md) (`≑`) doesn't depend on fills, and any attempt to compute a fill can't cause side effects.
+Fills are used by [Take](take.md) (`↑`) when a value in `𝕨` is larger than the corresponding length in `𝕩` and [Reshape](reshape.md) (`β₯Š`) when `𝕨` contains `↑`, by the two [Nudge](shift.md) functions (`»«`) when `𝕩` is non-empty, by [Merge](couple.md) (`>`) and [Join](join.md) when `𝕩` is empty, and by [Cells and Rank](rank.md) when the result has an empty frame. These are the only ways that an array's fill value can affect the program. The result of [Match](match.md) (`≑`) doesn't depend on fills, and any attempt to compute a fill can't cause side effects.
## Using fills
-For the examples in this section we'll use the fact that an all-number array usually has `0` as a fill while a string has `' '` (BQN maintains fills alongside array values rather than deriving them from arrays, so it's possible to construct arrays where this isn't true, but this probably wouldn't happen in ordinary code).
+For the examples in this section we'll use the fact that an all-number array usually has `0` as a fill while a string has `' '` (it's not too rare to end up with such an array that has no fill, and possible but very unusual for an array to have a fill that conflicts with those rules).
-[Take](take.md) (`↑`) and [Nudge](shift.md) (`»«`) in either direction use the fill for padding, to extend the array past its boundary. For example, `𝕨↑𝕩` will add elements to one side when a number in `|𝕨` is larger than the corresponding length in `≒𝕩`.
+[Take](take.md) (`↑`) and [Nudge](shift.md) (`»«`) in either direction use the fill for padding, to extend the array past its boundary. For example, `𝕨↑𝕩` adds elements to one side if a number in `|𝕨` is larger than the corresponding length in `≒𝕩`.
Β―7 ↑ 4β₯Š3 # Fill with 0
Β―7 ↑ "qrst" # Fill with space
-Nudge Left or Right shifts the array over and places a fill in the vacated space, effectively extending it backwards by one. If `𝕩` is empty then it shouldn't give an error, but it's safer not to rely on this.
+Nudge Left or Right shifts the array over and places a fill in the vacated space. If `𝕩` is empty then it doesn't need the fill and can't error.
Ȭ ⟨4β₯Š3,"qrst"⟩
@@ -24,8 +24,6 @@ Nudge Left or Right shifts the array over and places a fill in the vacated space
»⟨⟩ # Fill not needed
-If the argument to [Merge](couple.md) is empty then its result will be as well, since the shape `≒𝕩` is a prefix of `β‰’>𝕩`. However, the remainder of the result shape is determined by the elements of `𝕩`, so if there are none then Merge uses the fill element to decide what the result shape should be.
-
[Reshape](reshape.md#computed-lengths) (`β₯Š`) uses the fill when `𝕨` contains `↑` and the product of the rest of `𝕨` doesn't evenly divide the number of elements in `𝕩`.
↑‿8 β₯Š "completepart"
@@ -34,19 +32,33 @@ If for some reason you need to find an array's fill element, the easiest general
βŠ‘Β»1↑β₯Š"string"
+## Edge cases
+
+The above functions use the fill as part of their core definition. A few other functions use fills only when they encounter empty arrays. The goal of this behavior is to make programs working on empty arrays more similar to the non-empty case, so if all goes well you don't need to be thinking about these cases.
+
+If the argument to [Merge](couple.md) is empty then its result will be as well, since the shape `≒𝕩` is a prefix of `β‰’>𝕩`. However, the remainder of the result shape is determined by the elements of `𝕩`, so if there are none then Merge uses the fill element to decide what the result shape should be. [Join](join.md) is similar, although it multiplies the shape of `𝕩` by the leading shape of the fill instead of concatenating them.
+
+ β‰’ > 2β€Ώ0β₯Š<3β€Ώ4β€Ώ1β₯Š0
+
+ β‰’ ∾ 2β€Ώ0β₯Š<3β€Ώ4β€Ώ1β₯Š0
+
+[Cells and Rank](rank.md) rely on fills in a slightly more complicated way. If one of the argument frames is empty, that means the result will be empty, but the shape of a result cell still needs to be known to determine its shape (and similarly for the fill, but that's optional). BQN implementations may try to find it by running `𝔽` using a cell of fills for the argument. As in Each (`Β¨`) described below, this evaluation is not allowed to produce side effects. If it doesn't work, the result cell shape is assumed to be `⟨⟩`.
+
+ β‰’ ⌽˘ ↕0β€Ώ4β€Ώ3 # Shape is determined by fills
+
## How fills are computed
For the exact requirements placed on fill, see [the specification](../spec/inferred.md#fill-elements) (particularly "required functions"). This section loosely describes behavior in existing BQN implementations, and includes some parts that aren't required in the specification.
A fill element should encompass something that's necessarily true for all elements of an array. If the way an array is computed implies it's all numbers, the fill should be `0`. If every element is a list of two numbers, then the fill should be `⟨0,0⟩`. If every element is a list but the lengths might vary, `⟨⟩` is probably a reasonable fill element.
-For [arithmetic](arithmetic.md) primitives, the fill is found by the rules of pervasion, applying the function to both argument fills. Generally this means it consists of `0`, but character arithmetic also allows space fills.
+For [arithmetic](arithmetic.md) primitives, the fill is found by the rules of pervasion, applying the function to both argument fills. Generally this means it consists of `0`, but [character arithmetic](arithmetic.md#character-arithmetic) can produce space for a fill value.
Β» "abc" + 4β€Ώ3β€Ώ2
[Mapping](map.md) modifiers Each and Table (`¨⌜`) might try to follow a similar strategy, applying `𝔽` to argument fills to obtain the result fill. The absolute rule here is that this computation can't cause side effects or an error, so for a complicated `𝔽` such as a block function this procedure is likely to be aborted to avoid disrupting the rest of the program.
-Most other primitives fit in one of three broad categories as shown in the table below. Structural primitives, indicated by `⊒`, don't change the fill of `𝕩`. Combining structural primitives, indicated by `∩`, only depend on the fill of all combined arraysβ€”elements of `𝕩` in the one-argument case, or `𝕨` and `𝕩` in the two-argument case. Finally, many functions such as [search functions](search.md) return only numbers and have a fill of `0`.
+Most other primitives fit in one of three broad categories as shown in the table below. Structural primitives, indicated by `⊒`, don't change the fill of `𝕩`. Combining structural primitives, indicated by `∩`, only depend on the fill of all combined arraysβ€”elements of `𝕩` in the one-argument case, or `𝕨` and `𝕩` in the two-argument case. If these fills are the same value, then that's the fill; otherwise, the result has no fill. Finally, many functions such as [search functions](search.md) return only arrays of numbers and have a fill of `0`.
| Fill | Monads | Dyads | Modifiers
|--------|--------------|-------------|----------