aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2020-09-04 21:33:13 -0400
committerMarshall Lochbaum <mwlochbaum@gmail.com>2020-09-04 21:33:13 -0400
commit015d9cd399100427b3e82fb183c81d034f00cd8c (patch)
tree64470d2b546b3691483e35dcadaf925988ffcd37 /doc
parentcf072f50d2e1c600c788d37645721a94c55377c8 (diff)
Use atom for non-array throughout docs
Diffstat (limited to 'doc')
-rw-r--r--doc/couple.md2
-rw-r--r--doc/depth.md8
-rw-r--r--doc/group.md2
-rw-r--r--doc/indices.md8
-rw-r--r--doc/join.md2
-rw-r--r--doc/leading.md2
-rw-r--r--doc/transpose.md6
7 files changed, 15 insertions, 15 deletions
diff --git a/doc/couple.md b/doc/couple.md
index 3b11b2b3..3cc1ac8f 100644
--- a/doc/couple.md
+++ b/doc/couple.md
@@ -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 non-arrays 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 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`.
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 a1c900f3..13674e02 100644
--- a/doc/depth.md
+++ b/doc/depth.md
@@ -2,7 +2,7 @@
# Depth
-The depth of an array is the greatest level of array nesting it attains, or, put another way, the greatest number of times you can pick an element starting from the original array before reaching a non-array. The monadic function Depth (`≑`) returns the depth of its argument, while the 2-modifier Depth (`βš‡`) can control the way its left operand is applied based on the depth of its arguments. Several primitive functions also use the depth of the left argument to decide whether it applies to a single axis of the right argument or to several axes.
+The depth of an array is the greatest level of array nesting it attains, or, put another way, the greatest number of times you can pick an element starting from the original array before reaching an atom. The monadic function Depth (`≑`) returns the depth of its argument, while the 2-modifier Depth (`βš‡`) can control the way its left operand is applied based on the depth of its arguments. Several primitive functions also use the depth of the left argument to decide whether it applies to a single axis of the right argument or to several axes.
## The Depth function
@@ -22,7 +22,7 @@ Also unlike rank, Depth *does* care about the elements of its argument: in fact,
≑ ⟨2,<3,4,5⟩
≑ ⟨2,<3,4,<<<5⟩
-As the above expressions suggest, the depth of an array is the maximum of its elements' depths, plus one. The base case, a non-array (including a function or modifier), has depth 0.
+As the above expressions suggest, the depth of an array is the maximum of its elements' depths, plus one. The base case, an atom (including a function or modifier), has depth 0.
≑'c'
F←+⋄≑f
@@ -56,7 +56,7 @@ In these cases the flexibility seems trivial because the left argument has depth
⟨3β€Ώ2,1β€Ώ4β€Ώ1⟩ ⊏ ↕6β€Ώ7
-This means the left argument is homogeneous of depth 2. What should an argument of depth 1, or an argument that contains non-arrays, do? One option is to continue to require the left argument to be a list, and convert any non-array argument into an array by enclosing it:
+This means the left argument is homogeneous of depth 2. What should an argument of depth 1, that is, an array of atoms, do? One option is to continue to require the left argument to be a list, and convert any atom argument into an array by enclosing it:
⟨3β€Ώ2,1⟩ <⍟(0=≑)¨⊸⊏ ↕6β€Ώ7
@@ -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 loop until non-arrays are reached, 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 a scalar function.
⟨'a',"bc"⟩ β‰βš‡0 ⟨2β€Ώ3,4⟩
diff --git a/doc/group.md b/doc/group.md
index 17e05850..81e16f94 100644
--- a/doc/group.md
+++ b/doc/group.md
@@ -6,7 +6,7 @@ BQN replaces the [Key](https://aplwiki.com/wiki/Key) operator from J or Dyalog A
## Definition
-Group operates on a numeric list of indices and an array, treated as a list of its major cells or "values", to produce a list of groups, each of which is a selection from those cells. The two arrays have the same length, and each value cell is paired with the index at the same position. That index indicates the result group the cell should go into, with an "index" of Β―1 indicating that it should be dropped and not appear in the result.
+Group operates on a list of atomic-number indices and an array, treated as a list of its major cells or "values", to produce a list of groups, each of which is a selection from those cells. The two arrays have the same length, and each value cell is paired with the index at the same position. That index indicates the result group the cell should go into, with an "index" of Β―1 indicating that it should be dropped and not appear in the result.
0β€Ώ1β€Ώ2β€Ώ0β€Ώ1 ≍ "abcde" # Corresponding indices and values
0β€Ώ1β€Ώ2β€Ώ0β€Ώ1 βŠ” "abcde" # Values grouped by index
diff --git a/doc/indices.md b/doc/indices.md
index a210f710..b98f3c33 100644
--- a/doc/indices.md
+++ b/doc/indices.md
@@ -2,7 +2,7 @@
# Indices
-One-dimensional arrays such as K lists or Python arrays have only one kind of index, a single number that refers to an element. For multidimensional arrays using the [leading axis theory](leading.md), there are several types of indexing that can be useful. Historically, nested APL designs have equivocated between these, which I believe can lead to subtle errors when programming. BQN focuses on single-number (depth 0 or atomic) indices, which can refer to list elements or array major cells (or more generally indexing along any particular axis). When using atomic indices to select elements, the indexed array has to be a list. In contrast, elements of any array can be indicated by list indices, whose length is equal to the array's rank. Only two BQN primitives use these list indices: Range (`↕`), which returns an array of them if given a list argument, and Pick (`βŠ‘`), where the depth-1 components of an array left argument are list indices.
+One-dimensional arrays such as K lists or Python arrays have only one kind of index, a single number that refers to an element. For multidimensional arrays using the [leading axis theory](leading.md), there are several types of indexing that can be useful. Historically, nested APL designs have equivocated between these, which I believe can lead to subtle errors when programming. BQN focuses on single-number (atomic) indices, which can refer to list elements or array major cells (or more generally indexing along any particular axis). When using atomic indices to select elements, the indexed array has to be a list. In contrast, elements of any array can be indicated by list indices with length equal to that array's rank. Only two BQN primitives use these list indices: Range (`↕`), which returns an array of them if given a list argument, and Pick (`βŠ‘`), where the depth-1 components of an array left argument are list indices.
The following functions take or return indices. Except where marked, the indices are in the result; this is by far the most common type of index use. `βŠ”` is given two rows as it falls into both cases. Note that in the result case, there is usually no possibility for the programmer to select the format of indices. Instead, the language should be carefully designed to make sure that the kind of index returned is as useful as possible.
@@ -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 depth-0 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 prevents 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 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.
-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 single-number 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. A single scalar index 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. Single numbers 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 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?
# Major cell indices
@@ -50,6 +50,6 @@ To match this format, Range (`↕`) could be changed to return a flat array when
The most interesting feature would be that `⊏` could still allow a nested left argument. In this case each element of the left argument would be an array with row indices as before. However, each row can now index along multiple axes, allowing some adjacent axes to be dependent while others remain independent. This nicely unifies scatter-point and per-axis selection, and allows a mix of the two. However, it doesn't allow total freedom, as non-adjacent axes can't be combined except by also mixing in all axes in between.
-Group (`βŠ”`) could accept the same index format for its index argument. Each depth-1 array in the left argument would correspond to multiple axes in the outer result array, but only a single axis in the argument and inner arrays. Because the ravel ordering of indices must be used to order cells of inner arrays, this modification is not quite as clean as the change to Select. It's also not so clearly useful, as the same results can be obtained by using numeric indices and reshaping the result.
+Group (`βŠ”`) could accept the same index format for its index argument. Each depth-1 array in the left argument would correspond to multiple axes in the outer result array, but only a single axis in the argument and inner arrays. Because the ravel ordering of indices must be used to order cells of inner arrays, this modification is not quite as clean as the change to Select. It's also not so clearly useful, as the same results can be obtained by using atomic indices and reshaping the result.
Overall it seems to me that the main use of cell indices of the type discussed here is for the Select primitive, and the other cases are somewhat contrived an awkward. So I've chosen not to support it in BQN at all.
diff --git a/doc/join.md b/doc/join.md
index 05171e24..b1041c83 100644
--- a/doc/join.md
+++ b/doc/join.md
@@ -14,7 +14,7 @@ To join with a separator in between, we might prepend the separator to each stri
Join requires each element of its argument to be an array, and their ranks to match exactly. No rank extension is performed.
- ∾"abc"β€Ώ'd'β€Ώ"ef" # Includes a non-array
+ ∾"abc"β€Ώ'd'β€Ώ"ef" # Includes an atom
RANK ERROR
∾"abc"β€Ώ(<'d')β€Ώ"ef" # Includes a scalar
RANK ERROR
diff --git a/doc/leading.md b/doc/leading.md
index 35d72295..d11773d2 100644
--- a/doc/leading.md
+++ b/doc/leading.md
@@ -8,7 +8,7 @@ Several primitive functions manipulate the right argument, or sometimes both arg
### Manipulating cells
-Most non-scalar monadic functions work only on the first axis of the argumentβ€”that is, they treat it as a list of its major cells. The function Length (`β‰ `) counts these major cells, while Prefixes (`↑`), Suffixes (`↓`), Reverse (`⌽`), and First Cell (`⊏`) move them around. The Insert (`˝`) and Scan (`` ` ``) modifiers also yield functions that work along the first axis; in contrast, Reduce (`Β΄`) requires its argument to be a list, as it works on elements.
+Most non-arithmetic monadic functions work only on the first axis of the argumentβ€”that is, they treat it as a list of its major cells. The function Length (`β‰ `) counts these major cells, while Prefixes (`↑`), Suffixes (`↓`), Reverse (`⌽`), and First Cell (`⊏`) move them around. The Insert (`˝`) and Scan (`` ` ``) modifiers also yield functions that work along the first axis; in contrast, Reduce (`Β΄`) requires its argument to be a list, as it works on elements.
⊒ a ← 3β€Ώ2 β₯Š "abcdef" # An array with three major cells
⊏ a # Get the first major cell
diff --git a/doc/transpose.md b/doc/transpose.md
index f7034e83..ae72d889 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.
-A non-array right argument to Transpose is always enclosed to get a scalar array before doing anything else.
+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 for scalar arguments it returns the array 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.
-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.
+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.