diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2020-09-20 13:50:30 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2020-09-20 13:50:30 -0400 |
| commit | f910f64594053011efd57a97100ad19ee1e39fb4 (patch) | |
| tree | 33550f94bf4c2ea035e73d6e37395de299e4ab11 /doc | |
| parent | bfc6eb1fcc5408ecf415224d47494a4005330da8 (diff) | |
Use "unit" or "rank-0" instead of "scalar"
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/based.md | 12 | ||||
| -rw-r--r-- | doc/couple.md | 8 | ||||
| -rw-r--r-- | doc/depth.md | 2 | ||||
| -rw-r--r-- | doc/indices.md | 24 | ||||
| -rw-r--r-- | doc/join.md | 2 | ||||
| -rw-r--r-- | doc/leading.md | 6 | ||||
| -rw-r--r-- | doc/transpose.md | 4 | ||||
| -rw-r--r-- | doc/windows.md | 2 |
8 files changed, 30 insertions, 30 deletions
diff --git a/doc/based.md b/doc/based.md index 1f542233..b9c5d3e9 100644 --- a/doc/based.md +++ b/doc/based.md @@ -12,9 +12,9 @@ If you're an array programmer then I have bad news for you. My thesis here is th APL tends to define its data by starting with the array and then looking downwards in depth at what it contains. The based array model, as the name suggests, starts at the foundations, which in BQN are called "atoms". There are five types of atom, which together with the array type give the six types a value can have in BQN. Based means being yourself, and an atom's *not* an array. -An atom has [depth](depth.md) 0, and doesn't inherently have a shape. However, primitives that expect an array promote atoms by enclosing them to get a scalar containing the atom. Rank and shape both do this, so an atom can be considered to have the same dimensions as a scalar: rank 0 and shape `⟨⟩`. +An atom has [depth](depth.md) 0, and doesn't inherently have a shape. However, primitives that expect an array promote atoms by enclosing them to get a rank-0, or *unit*, array that contains the atom (any value can be enclosed in this way, giving a unit array with higher depth, but it only happens automatically for atoms). Rank and shape both do this, so an atom can be considered to have the same dimensions as a unit array: rank 0 and shape `⟨⟩`. An atom is also considered a kind of unit, but it's not a unit array. -Atoms are displayed as plain values, while boxed atoms (that is, depth-1 scalar arrays) are shown with an array display. +Atoms are displayed as plain values, while enclosed atoms, that is, depth-1 unit arrays, are shown with an array display. 3 # Atom <3 # Array @@ -40,9 +40,9 @@ Arrays in BQN, like nearly all data structures in modern programming languages, ## Versus the nested array model -The [nested array model](https://aplwiki.com/wiki/Array_model#Nested_array_theory) of NARS, APL2, Dyalog, and GNU APL can be constructed from the based model by adding a rule: a scalar array containing an atom is equivalent to that atom. The equivalents of atoms in nested array theory are thus called "simple scalars", and they are considered arrays but share the characteristics of BQN atoms. Nested arrays don't form an inductive type, because simple scalars contain themselves. +The [nested array model](https://aplwiki.com/wiki/Array_model#Nested_array_theory) of NARS, APL2, Dyalog, and GNU APL can be constructed from the based model by adding a rule: a unit (or "scalar" in APL) array containing an atom is equivalent to that atom. The equivalents of atoms in nested array theory are thus called "simple scalars", and they are considered arrays but share the characteristics of BQN atoms. Nested arrays don't form an inductive type, because simple scalars contain themselves. -Nested array theory can seem simpler to use, because the programmer never has to worry about simple scalars being enclosed the wrong number of times: all these encloses have been identified with each other. For example, `'abcd'[2]` returns a character while BQN's `2⊏"abcd"` returns a scalar containing a character. However, these issues usually still appear with more complex arrays: `'ab' 1 'ef'[2]` (here spaces are used for stranding) is not a string but an enclosed string! +Nested array theory can seem simpler to use, because the programmer never has to worry about simple scalars being enclosed the wrong number of times: all these encloses have been identified with each other. For example, `'abcd'[2]` returns a character while BQN's `2⊏"abcd"` returns an array containing a character. However, these issues usually still appear with more complex arrays: `'ab' 1 'ef'[2]` (here spaces are used for stranding) is not a string but an enclosed string! A property that might warn about dangerous issues like this is that nested array theory tends to create *inversions* where the depth of a particular array depends on its rank (reversing the normal hierarchy of depth→rank→shape). A 1-character string has depth 1, but when its rank is reduced to 0, its depth is reduced as well. @@ -50,8 +50,8 @@ In some cases nested array theory can remove a depth issue entirely, and not jus ## Versus the boxed array model -The [boxed array model](https://aplwiki.com/wiki/Array_model#Boxes) of SHARP APL, A+, and J is an inductive system like BQN's. But this model uses arrays as the base case: numeric and character arrays are the simplest kind of data allowed, and "a number" means a scalar numeric array. The inductive step is the array of boxes; as with numbers "a box" is simply a scalar array of boxes. +The [boxed array model](https://aplwiki.com/wiki/Array_model#Boxes) of SHARP APL, A+, and J is an inductive system like BQN's. But this model uses arrays as the base case: numeric and character arrays are the simplest kind of data allowed, and "a number" means a rank-0 numeric array. The inductive step is the array of boxes; as with numbers "a box" is simply a rank-0 array of boxes. -Numeric and character arrays in this system have depth 0. In general these correspond to arrays of depth 1 in BQN, but because there's no lower depth they are also used where BQN atoms would appear. For example, both Shape (`$`) and Length (`#`) return depth-0 results in J. For a non-scalar array `a`, the length `#a` is exactly `[/ $ a`, while the identical BQN code `⊣˝ ≢ a` returns not `≠ a` but `< ≠ a`. Like the nested model, the boxed model can hide depth issues that occur at lower depths but generally reveals them at higher depths. +Numeric and character arrays in this system have depth 0. In general these correspond to arrays of depth 1 in BQN, but because there's no lower depth they are also used where BQN atoms would appear. For example, both Shape (`$`) and Length (`#`) return depth-0 results in J. For an array `a` with rank at least 1, the length `#a` is exactly `[/ $ a`, while the identical BQN code `⊣˝ ≢ a` returns not `≠ a` but `< ≠ a`. Like the nested model, the boxed model can hide depth issues that occur at lower depths but generally reveals them at higher depths. The boundary at depth 0 will tend to cause inconsistencies and confusion in any array language, and boxed array languages push this boundary up a level. This leads to the programmer spending more effort managing boxes: for example, to reverse each list in a list of lists, the programmer can use reverse under open, `|. &. >`. But to find the lengths of each of these lists, `# &. >` would yield a boxed list, which is usually not wanted, so `# @ >` is needed instead. BQN shows that a system that doesn't require these distinctions is possible, as a BQN programmer would use `⌽¨` and `≠¨`. diff --git a/doc/couple.md b/doc/couple.md index 3cc1ac8f..f78d441c 100644 --- a/doc/couple.md +++ b/doc/couple.md @@ -30,7 +30,7 @@ In all cases what these functions do is more like reinterpreting existing data t ⥊ ⥊¨ a ∾ ⥊ ⥊¨ a -The way this happens, and the constraint that all inner arrays have the same shape, is closely connected to the concept of an array, and like Table `⌜`, Merge might be considered a fundamental way to build up multidimensional arrays from lists. In both cases scalars are somewhat special. They are the identity element of a function with Table, and can be produced by Merge inverse, `>⁼` **on a list**, which forces either the outer or inner shape to be empty (BQN chooses `>⁼` to be `<`, but only on an array, as `>` cannot produce non-arrays). Merge has another catch as well: it cannot produce arrays with a `0` in the shape, except at the end, without some sort of prototype system. +The way this happens, and the constraint that all inner arrays have the same shape, is closely connected to the concept of an array, and like Table `⌜`, Merge might be considered a fundamental way to build up multidimensional arrays from lists. In both cases rank-0 or unit arrays are somewhat special. They are the identity element of a function with Table, and can be produced by Merge inverse, `>⁼` **on a list**, which forces either the outer or inner shape to be empty (BQN chooses `>⁼` to be `<`, but only on an array, as `>` cannot produce non-arrays). Merge has another catch as well: it cannot produce arrays with a `0` in the shape, except at the end, without some sort of prototype system. ⊢ e ← ⟨⟩¨ ↕3 ≢ > e @@ -38,9 +38,9 @@ The way this happens, and the constraint that all inner arrays have the same sha Above we start with a list of three empty arrays. After merging once we get a shape `3‿0` array, sure, but what happens next? The shape added by another merge is the shared shape of that array's elements—and there aren't any! If the nested list kept some type information around then we might know, but extra type information is essentially how lists pretend to be arrays. True dynamic lists simply can't represent multidimensional arrays with a `0` in the middle of the shape. In this sense, arrays are a richer model than nested lists. -## Coupling scalars +## Coupling units -A note on the topic of Solo and Couple applied to scalars. As always, one axis will be added, so that the result is a list (strangely, J's [laminate](https://code.jsoftware.com/wiki/Vocabulary/commaco#dyadic) differs from Couple in this one case, as it will add an axis to get a shape `2‿1` result). For Solo, this is interchangeable with Deshape (`⥊`), and either primitive might be chosen for stylistic reasons. For Couple, it is equivalent to Join-to (`∾`), but this is an irregular form of Join-to because it is the only case where Join-to adds an axis to both arguments instead of just one. Couple should be preferred in this case. +A note on the topic of Solo and Couple applied to units. As always, one axis will be added, so that the result is a list (strangely, J's [laminate](https://code.jsoftware.com/wiki/Vocabulary/commaco#dyadic) differs from Couple in this one case, as it will add an axis to get a shape `2‿1` result). For Solo, this is interchangeable with Deshape (`⥊`), and either primitive might be chosen for stylistic reasons. For Couple, it is equivalent to Join-to (`∾`), but this is an irregular form of Join-to because it is the only case where Join-to adds an axis to both arguments instead of just one. Couple should be preferred in this case. The pair function, which creates a list from its arguments, can be written `Pair ← ≍○<`, while `≍` in either valence is `>∘Pair`. As an interesting consequence, `≍ ←→ >∘≍○<`, and the same relationship holds for `Pair`. @@ -49,6 +49,6 @@ The pair function, which creates a list from its arguments, can be written `Pair ## Definitions -As discussed above, `≍` is equivalent to `>{⟨𝕩⟩;⟨𝕨,𝕩⟩}`. To complete the picture we should describe Merge fully. Merge is defined on an array argument `𝕩` such that there's some shape `s` satisfying `∧´⥊(s≡≢)¨𝕩`. If `𝕩` is empty then any shape satisfies this expression; `s` should be chosen based on known type information for `𝕩` or otherwise assumed to be `⟨⟩`. If `s` is empty then `𝕩` is allowed to contain atoms as well as array scalars, and these will be implicitly promoted to arrays by the `⊑` indexing used later. We construct the result by combining the outer and inner axes of the argument with Table; since the outer axes come first they must correspond to the left argument and the inner axes must correspond to the right argument. `𝕩` is a natural choice of left argument, and because no concrete array can be used, the right argument will be `↕s`, the array of indices into any element of `𝕩`. To get the appropriate element corresponding to a particular choice of index and element of `𝕩` we should select using that index. The result of Merge is `𝕩⊑˜⌜↕s`. +As discussed above, `≍` is equivalent to `>{⟨𝕩⟩;⟨𝕨,𝕩⟩}`. To complete the picture we should describe Merge fully. Merge is defined on an array argument `𝕩` such that there's some shape `s` satisfying `∧´⥊(s≡≢)¨𝕩`. If `𝕩` is empty then any shape satisfies this expression; `s` should be chosen based on known type information for `𝕩` or otherwise assumed to be `⟨⟩`. If `s` is empty then `𝕩` is allowed to contain atoms as well as unit arrays, and these will be implicitly promoted to arrays by the `⊑` indexing used later. We construct the result by combining the outer and inner axes of the argument with Table; since the outer axes come first they must correspond to the left argument and the inner axes must correspond to the right argument. `𝕩` is a natural choice of left argument, and because no concrete array can be used, the right argument will be `↕s`, the array of indices into any element of `𝕩`. To get the appropriate element corresponding to a particular choice of index and element of `𝕩` we should select using that index. The result of Merge is `𝕩⊑˜⌜↕s`. Given this definition we can also describe Rank (`⎉`) in terms of Each (`¨`) and the simpler monadic function Enclose-Rank `<⎉k`. We assume effective ranks `j` for `𝕨` (if present) and `k` for `𝕩` have been computed. Then the correspondence is `𝕨F⎉k𝕩 ←→ >(<⎉j𝕨)F¨(<⎉k𝕩)`. diff --git a/doc/depth.md b/doc/depth.md index 13674e02..f2dfe34a 100644 --- a/doc/depth.md +++ b/doc/depth.md @@ -86,7 +86,7 @@ Depth `¯1` is equivalent to Each, and reverses the larger vectors, while depth ⌽⚇¯1 n ⌽⚇¯2 n -While a negative depth tells how many levels to go down, a non-negative depth gives the maximum depth of the argument before applying the left operand. On a depth-3 array like above, depth `2` is equivalent to `¯1` and depth `1` is equivalent to `¯2`. A depth of `0` means to descend all the way to the level of atoms, that is, apply [pervasively](https://aplwiki.com/wiki/Pervasion), like a scalar function. +While a negative depth tells how many levels to go down, a non-negative depth gives the maximum depth of the argument before applying the left operand. On a depth-3 array like above, depth `2` is equivalent to `¯1` and depth `1` is equivalent to `¯2`. A depth of `0` means to descend all the way to the level of atoms, that is, apply [pervasively](https://aplwiki.com/wiki/Pervasion), like an arithmetic function. ⟨'a',"bc"⟩ ≍⚇0 ⟨2‿3,4⟩ diff --git a/doc/indices.md b/doc/indices.md index b98f3c33..ec149a09 100644 --- a/doc/indices.md +++ b/doc/indices.md @@ -8,17 +8,17 @@ The following functions take or return indices. Except where marked, the indices | Monad | Dyad | Where | How |-------|------|---------|-------------------------- -| `↕` | | | Element scalar or list -| `/` | | | Element scalar -| `⊔` | | | Element scalar -| `⊔` | `⊔` | `𝕩`/`𝕨` | Along-axis scalar +| `↕` | | | Element number or list +| `/` | | | Element number +| `⊔` | | | Element number +| `⊔` | `⊔` | `𝕩`/`𝕨` | Along-axis number | | `⊑` | `𝕨` | Element list -| `⍋` | `⍋` | | Major cell scalar -| `⍒` | `⍒` | | Major cell scalar -| | `⊐` | | Major cell scalar -| | `⊒` | | Major cell scalar -| | `⊏` | `𝕨` | Major cell or along-axis scalar -| `⍉` | | | Axis scalar +| `⍋` | `⍋` | | Major cell number +| `⍒` | `⍒` | | Major cell number +| | `⊐` | | Major cell number +| | `⊒` | | Major cell number +| | `⊏` | `𝕨` | Major cell or along-axis number +| `⍉` | | | Axis number Dyadic Transpose (`⍉`) uses indices into the right argument axes in its left argument, but since array shape is 1-dimensional, there is only one sensible choice for this, a single number. @@ -26,9 +26,9 @@ Dyadic Transpose (`⍉`) uses indices into the right argument axes in its left a In general, the index of an element of an array is a list whose length matches the array rank. It is also possible to use a number for an index into a list, as the list index is a singleton, but this must be kept consistent with the rest of the language. NARS-family APLs make the Index Generator (`↕` in BQN) return a numeric list when the argument has length 1 but a nested array otherwise. This means that the depth of the result depends on the shape of the argument, inverting the typical hierarchy. BQN shouldn't have such an inconsistency. -Functions `↕`, `/`, `⊔`, and `⊑` naturally deal with element indices. Each of these can be defined to use list indices. However, this usually rules out the possibility of using scalar indices, which makes these functions harder to use both with generic array manipulation and with the major cell indices discussed in the next section. For this reason BQN restricts `⊔` and monadic `/` to use atomic indices, which comes with the requirement that the arguments to monadic `/` and `⊔`, and the result of monadic `⊔`, must be lists. For dyadic `⊔` the depth-1 elements of the left argument are lists of indices along axes of the result; see [the documentation](group.md#multidimensional-grouping). The restriction that comes from using single-number indices is that all axes must be treated independently, so that for example it isn't possible to group elements along diagonals without preprocessing. However, this restriction also keeps Group from having to use an ordering on list indices. +Functions `↕`, `/`, `⊔`, and `⊑` naturally deal with element indices. Each of these can be defined to use list indices. However, this usually rules out the possibility of using atomic indices, which makes these functions harder to use both with generic array manipulation and with the major cell indices discussed in the next section. For this reason BQN restricts `⊔` and monadic `/` to use atomic indices, which comes with the requirement that the arguments to monadic `/` and `⊔`, and the result of monadic `⊔`, must be lists. For dyadic `⊔` the depth-1 elements of the left argument are lists of indices along axes of the result; see [the documentation](group.md#multidimensional-grouping). The restriction that comes from using single-number indices is that all axes must be treated independently, so that for example it isn't possible to group elements along diagonals without preprocessing. However, this restriction also keeps Group from having to use an ordering on list indices. -Unlike `/` and `⊔`, `↕` and `⊑` do use list element indices. For `↕` this is because the output format can be controlled by the argument format: if passed a single number, the result uses atomic indices (so it's a numeric list); if passed a list, it uses list indices and the result has depth 2 (the result depth is always one greater than the argument depth). For `⊑`, list indices are chosen because `⊏` handles scalar indices well already. When selecting multiple elements from a list, they would typically have to be placed in an array, which is equivalent to `⊏` with a numeric list left argument. An atomic left argument to `⊑` is converted to a list, so it can be used to select a single element if only one is wanted. To select multiple elements, `⊑` uses each depth-1 array in the left argument as an index and replaces it with that element from the right argument. Because this uses elements as elements (not cells), it is impossible to have conformability errors where elements do not fit together. Ill-formed index errors are of course still possible, and the requirements on indices are quite strict. They must exactly match the structure of the right argument's shape, with no scalars or higher-rank arrays allowed. Atoms also cannot be used in this context, as it would create ambiguity: is a one-element list an index, or does it contain an index? +Unlike `/` and `⊔`, `↕` and `⊑` do use list element indices. For `↕` this is because the output format can be controlled by the argument format: if passed a single number, the result uses atomic indices (so it's a numeric list); if passed a list, it uses list indices and the result has depth 2 (the result depth is always one greater than the argument depth). For `⊑`, list indices are chosen because `⊏` handles atomic indices well already. When selecting multiple elements from a list, they would typically have to be placed in an array, which is equivalent to `⊏` with a numeric list left argument. An atomic left argument to `⊑` is converted to a list, so it can be used to select a single element if only one is wanted. To select multiple elements, `⊑` uses each depth-1 array in the left argument as an index and replaces it with that element from the right argument. Because this uses elements as elements (not cells), it is impossible to have conformability errors where elements do not fit together. Ill-formed index errors are of course still possible, and the requirements on indices are quite strict. They must exactly match the structure of the right argument's shape, with no units or higher-rank arrays allowed. Atoms also cannot be used in this context, as it would create ambiguity: is a one-element list an index, or does it contain an index? # Major cell indices diff --git a/doc/join.md b/doc/join.md index b1041c83..3b42069f 100644 --- a/doc/join.md +++ b/doc/join.md @@ -16,7 +16,7 @@ Join requires each element of its argument to be an array, and their ranks to ma ∾"abc"‿'d'‿"ef" # Includes an atom RANK ERROR - ∾"abc"‿(<'d')‿"ef" # Includes a scalar + ∾"abc"‿(<'d')‿"ef" # Includes a unit RANK ERROR However, Join has higher-dimensional uses as well. Given a rank-`m` array of rank-`n` arrays (requiring `m≤n`), it will merge arrays along their first `m` axes. For example, if the argument is a matrix of matrices representing a [block matrix](https://en.wikipedia.org/wiki/Block_matrix), Join will give the corresponding unblocked matrix as its result. diff --git a/doc/leading.md b/doc/leading.md index d11773d2..43024a3c 100644 --- a/doc/leading.md +++ b/doc/leading.md @@ -55,7 +55,7 @@ Not all functions work on the first axis in a straightforward manner. [Transpose The other two monadic functions that work on high-rank arguments are Deshape (`⥊`) and First (`⊑`). These treat the argument as one long list, ordered by its element indices. This ordering privileges leading axes (in fact, it is the reason for the choice of leading axes in the leading axis convention), but these functions can't really be said to work on leading axes: they apply to all axes. -The Each (`¨`) and Table (`⌜`) modifiers return functions which are the same in the monadic case. These functions simply go through all elements of the argument array without regard for its multi-dimensional structure (the operand is applied to elements in index order, matching Deshape; this matters if it has side effects). Similarly, monadic scalar functions do not have any sort of leading axis dependence. +The Each (`¨`) and Table (`⌜`) modifiers return functions which are the same in the monadic case. These functions simply go through all elements of the argument array without regard for its multi-dimensional structure (the operand is applied to elements in index order, matching Deshape; this matters if it has side effects). Similarly, monadic arithmetic functions do not have any sort of leading axis dependence. ## Dyadic functions @@ -82,7 +82,7 @@ Functions with single-axis depth 1 tend to be more complicated; see for example ### Leading axis agreement -Scalar functions, and the Each (`¨`) and Depth (`⚇`) modifiers, use leading axis agreement to match their arguments together. All axes of the lower-rank argument are matched with the leading axes of the higher-rank one, and axes matched together must have the same length. After pairing axes in this way, a single element of the lower-rank argument might correspond to any number of elements of the higher-rank one. It's reused for each of those corresponding elements. +Arithmetic functions, and the Each (`¨`) and Depth (`⚇`) modifiers, use leading axis agreement to match their arguments together. All axes of the lower-rank argument are matched with the leading axes of the higher-rank one, and axes matched together must have the same length. After pairing axes in this way, a single element of the lower-rank argument might correspond to any number of elements of the higher-rank one. It's reused for each of those corresponding elements. ⊢ x ← 3‿2‿4 ⥊ ↕60 # A rank-3 array 100‿0‿200 + x # 0-cells paired with 2-cells @@ -90,7 +90,7 @@ Scalar functions, and the Each (`¨`) and Depth (`⚇`) modifiers, use leading a c + x # 0-cells paired with 1-cells x + x # Pairwise addition -If one argument is a scalar, that is, it has no axes, then leading axis agreement reduces to "scalar extension", where a single scalar is matched with an entire array by repeating it at every application. A scalar always agrees with any other array under leading axis agreement because it has no axes whose lengths would need to be checked. +If one argument is a unit, that is, it has no axes, then leading axis agreement reduces to APL's "scalar extension" (where "scalar" is equivalent to BQN's "unit"), where a single unit is matched with an entire array by repeating it at every application. A unit always agrees with any other array under leading axis agreement because it has no axes whose lengths would need to be checked. With leading axis agreement, there are `k+1` shapes for arrays that can be added (or any other function with Each) to a given array `x` without changing its rank. These are precisely the prefixes of `≢x`, with ranks from `0` to `k` inclusive. Arrays with larger rank can also be used as the other argument, but then the result shape will match that argument and not `x`. diff --git a/doc/transpose.md b/doc/transpose.md index 1a870347..f8593e5a 100644 --- a/doc/transpose.md +++ b/doc/transpose.md @@ -74,8 +74,8 @@ Finally, it's worth noting that, as monadic Transpose moves the first axis to th Here we define the two valences of Transpose more precisely. -Monadic transpose is identical to `(=-1˙)⊸⍉`, except that for scalar arguments (including atoms) it returns the array unchanged rather than giving an error. +Monadic transpose is identical to `(=-1˙)⊸⍉`, except that if the argument is a unit it is returned unchanged rather than giving an error. -An atom right argument to dyadic Transpose is always enclosed to get a scalar array before doing anything else. +An atom right argument to dyadic Transpose is always enclosed to get an array before doing anything else. In dyadic Transpose, the left argument is a number or numeric array of rank 1 or less, and `𝕨≤○≠≢𝕩`. Define the result rank `r←(=𝕩)-+´¬∊𝕨` to be the argument rank minus the number of duplicate entries in the left argument. We require `∧´𝕨<r`. Bring `𝕨` to full length by appending the missing indices: `𝕨∾↩𝕨(¬∘∊˜/⊢)↕r`. Now the result shape is defined to be `⌊´¨𝕨⊔≢𝕩`. Element `i⊑z` of the result `z` is element `(𝕨⊏i)⊑𝕩` of the argument. diff --git a/doc/windows.md b/doc/windows.md index 2f1eda55..c46bbfcb 100644 --- a/doc/windows.md +++ b/doc/windows.md @@ -37,7 +37,7 @@ If the left argument has length `0`, then the argument is not sliced along any d ### More formally -`𝕩` is an array. `𝕨` is a number or numeric list or scalar with `𝕨≤○≠≢𝕩`. The result `z` has shape `𝕨∾¬⟜𝕨⌾((≠𝕨)⊸↑)≢𝕩`, and element `i⊑z` is `𝕩⊑˜(≠𝕨)(↑+⌾((≠𝕨)⊸↑)↓)i`. +`𝕩` is an array. `𝕨` is a number, or numeric list or unit, with `𝕨≤○≠≢𝕩`. The result `z` has shape `𝕨∾¬⟜𝕨⌾((≠𝕨)⊸↑)≢𝕩`, and element `i⊑z` is `𝕩⊑˜(≠𝕨)(↑+⌾((≠𝕨)⊸↑)↓)i`. Using [Group](group.md) we could also write `i⊑z` ←→ `𝕩⊑˜(𝕨∾○(↕∘≠)≢𝕩) +´¨∘⊔ i`. |
