aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2022-06-02 22:30:39 -0400
committerMarshall Lochbaum <mwlochbaum@gmail.com>2022-06-02 22:30:39 -0400
commitbd8c5efa3a9aa79df09016bfd9c047023e7cf75d (patch)
treee5317178e80caa9457ec99e614821f2284a81d5f /doc
parentc3ea468236e362e4ecc1bc27aed7a64d90e7cf81 (diff)
Editing
Diffstat (limited to 'doc')
-rw-r--r--doc/indices.md28
-rw-r--r--doc/join.md6
2 files changed, 18 insertions, 16 deletions
diff --git a/doc/indices.md b/doc/indices.md
index b2db1603..1b857466 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](array.md) 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. An element of an arbitrary array can be indicated by an index list as long as that array's rank. Only two BQN primitives use these index lists: [Range](range.md) (`↕`), which returns an array of them if given a list argument, and [Pick](pick.md) (`⊑`), where the depth-1 components of an array left argument are index lists.
+One-dimensional arrays like you might find in Python, Java, or K have only one kind of index, a single number that refers to an element. For [multidimensional arrays](array.md) 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. An element of an arbitrary array can be indicated by an index list as long as that array's rank. Only two BQN primitives use these index lists: [Range](range.md) (`↕`), which returns an array of them if given a list argument, and [Pick](pick.md) (`⊑`), where the depth-1 components of an array left argument are index lists.
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. [Group](group.md) (`⊔`) 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.
@@ -18,7 +18,7 @@ The following functions take or return indices. Except where marked, the indices
| | `⊐` | | Major cell number
| | `⊒` | | Major cell number
| | `⊏` | `𝕨` | Major cell or along-axis number
-| `⍉` | | | Axis number
+| | `⍉` | `𝕨` | Axis number
In [Reorder Axes](transpose.md#reorder-axes) (`⍉`), `𝕨` is made up of indices into axes of `𝕩`. Since array shape is 1-dimensional, there is only one sensible choice for these elements, a single number each.
@@ -26,30 +26,30 @@ In [Reorder Axes](transpose.md#reorder-axes) (`⍉`), `𝕨` is made up of indic
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 index list 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 [Range](range.md) (`↕`), [Indices](replicate.md) (`/`), [Group](group.md) (`⊔`), and [Pick](pick.md) (`⊑`) naturally deal with element indices. Each of these can be defined to use index lists. 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 `/` to use atomic indices, which comes with the requirement that the arguments to Group and Indices, and the result of Group Indices, must be lists. For dyadic Group the depth-1 elements of `𝕨` are arrays of indices along axes of the result ([multi-axis documentation](group.md#multidimensional-grouping)). This means each axis of `𝕩` can only be related to one axis of the result.
+Functions [Range](range.md) (`↕`), [Indices](replicate.md) (`/`), [Group](group.md) (`⊔`), and [Pick](pick.md) (`⊑`) naturally deal with element indices. Each of these can be defined to use index lists. 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 `/` to use atomic indices, which comes with the requirement that the arguments to Group and Indices, and the result of Group Indices, must be lists. [For dyadic Group](group.md#multidimensional-grouping) the depth-1 elements of `𝕨` are arrays of indices along axes of the result. This means each axis of `𝕩` can only be related to one axis of the result.
-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 index lists and the result has depth 2 (the result depth is always one greater than the argument depth). For `⊑`, index lists are chosen because [Select](select.md) (`⊏`) 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 `𝕨`. An atom `𝕨` in Pick 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 `𝕨` 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 (invalid index errors are of course still possible). 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 index lists and the result has depth 2 (the result depth is always one greater than the argument depth). For `⊑`, index lists are chosen because [Select](select.md) (`⊏`) 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 `𝕨`. Pick can convert `𝕨` from an atom to a list, so it's still convenient to select a single element. To select multiple elements, `⊑` uses each depth-1 array in `𝕨` as an index and replaces it with that element from the right argument. Because this uses elements as elements, not cells, it's impossible to have conformability errors where elements don't fit together. Unfortunately, atoms can't 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
-One of the successes of the [leading axis model](https://aplwiki.com/wiki/Leading_axis_theory) is to introduce a kind of index for multidimensional arrays that is easier to work with than index lists. The model introduces [cells](https://aplwiki.com/wiki/Cell), where a cell index is a list of any length up to the containing array's rank. General cell indices are discussed in the next section; first we introduce a special case, indices into major cells or ¯1-cells. These cells naturally form a list, so the index of a major cell is a single number. Such an index can also be considered to select along the first axis, since an index along any axis is a single number.
+One of the successes of the [leading axis model](https://aplwiki.com/wiki/Leading_axis_theory) is to introduce a kind of index for multidimensional arrays that is easier to work with than index lists. The model introduces [cells](https://aplwiki.com/wiki/Cell), where a cell index is a list of any length up to the containing array's rank. General cell indices are discussed in the next section; first we introduce a special case, indices into major cells or ¯1-cells. These cells are arranged along just the first axis, so the index of a major cell is one number.
-[Ordering](order.md) functions `⍋⍒` and [search](search.md)/[self-search](selfcmp.md) functions `⊐⊒` that depend on cell ordering only really make sense with major cell indices: while other indices have an ordering, it's not very natural. Note that `⊐` only uses the ordering in an incidental way, because it's defined to return the *first* index where a cell in `𝕩` is found. A mathematician would be more interested in a "pre-image" function that returns the set of all indices where a particular value appears. However, programming usefulness and consistency with the other search functions makes searching for the first index a reasonable choice.
+[Ordering](order.md) functions `⍋⍒` and [search](search.md)/[self-search](selfcmp.md) functions `⊐⊒` that depend on cell ordering only really make sense with major cell indices: while other indices have an ordering, it's not very natural. Note that Classify/Index-of (`⊐`) only uses the ordering in an incidental way, because it's defined to return the *first* index where a cell in `𝕩` is found. A pure mathematician would be more interested in a "pre-image" function that returns the set of all indices where a particular value appears. However, programming usefulness and consistency with the other search functions make searching for the first index a reasonable choice.
-Only one other function—but an important one!—deals with cells rather than elements: [Select](select.md) (`⊏`). Select [allows](leading.md#multiple-axes) either a simple first-axis case where `𝕨` has depth 1 or less (a depth-0 argument is automatically enclosed), and a multi-axis case where it is a list of depth-1 elements. In each case the depth-1 arrays index along a single axis.
+Only one other function—but an important one!—deals with cells rather than elements: [Select](select.md) (`⊏`). Select [allows](leading.md#multiple-axes) either a simple first-axis case where `𝕨` has depth 1 or less (a depth-0 argument is automatically enclosed), and a multi-axis case where it's a list of depth-1 elements. In each case the depth-1 arrays index along a single axis.
## General cell indices
-BQN does not use general cell indices directly, but it is useful to consider how they might work, and how a programmer might implement functions that use them in BQN if needed. The functions `/`, `⊔`, and `⊏` are the ones that can work with indices for multidimensional arrays but don't already. Here we will examine how multidimensional versions would work.
+BQN doesn't use general cell indices directly, but it's useful to consider how they might work, and how a programmer might implement functions that use them if needed. The functions `/`, `⊔`, and `⊏` are the ones that can work with indices for multidimensional arrays but don't already, so let's look at how that would be defined.
-A cell index into an array of rank `r` is a numeric list of length `l≤r`, which then refers to a cell of rank `r-l`. In BQN, the cell at index `i` of array `a` is `i<¨⊸⊏a`.
+A cell index into an array of rank `r` is a numeric list of length `l≤r`, which refers to a [cell](https://aplwiki.com/wiki/Cell) of rank `r-l`: the cell at index `i` of array `a` is `i<¨⊸⊏a`.
-Because the shape of a cell index relates to the shape of the indexed array, it makes sense not to enclose cell indices, instead treating them as rows of an index array. A definition for `⊏` for depth-1 left arguments of rank at least 1 follows: replace each row of the left argument with the indexed cell of the right, yielding a result with the same depth as the right argument and shape `𝕨((¯1↓⊣)∾(¯1↑⊣)⊸↓)○≢𝕩`.
+Because indices for cells of the same rank have the same shape, it makes sense to make multiple k-cell indices the rows of an array instead of enclosing them. Here's a definition for Select (`⊏`) when `𝕨` is an array of numbers with rank 1 or more: replace each row of `𝕨` with the cell of `𝕩` that it indicates, yielding a result with the same depth as `𝕩` and shape `(¯1↓≢𝕨)∾(¯1⊑≢𝕨)↓≢𝕩`.
-To match this format, Range (`↕`) could be changed to return a flat array when given a shape—what is now `>↕`. Following this pattern, Indices (`/`) would also return a flat array, where the indices are rows: using the modified Range, `⥊/↕∘≢`. Here the result cannot retain the argument's array structure; it is always a rank-2 list of rows.
+To match this format, Range (`↕`) could be changed to return a flat array when given a shape `𝕩`—what is now `>↕`. Following this pattern, Indices (`/`) would also return a flat array, where the indices are rows: using the modified Range, `⥊/↕∘≢`. Here the result cannot retain the argument's array structure; it's always a rank-2 list of rows.
-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.
+The most interesting feature would be that Select could still allow `𝕨` to be nested. In this case each element of `𝕨` would be an array with cell indices for its rows 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 atomic indices and reshaping the result.
+Group (`⊔`) could accept the same index format for its index argument `𝕨`. Each depth-1 array in `𝕨` would correspond to multiple axes in the outer result array, but only a single axis in `𝕩` 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.
+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 and awkward. So I've chosen not to support it in BQN at all.
diff --git a/doc/join.md b/doc/join.md
index 656a12db..b687a946 100644
--- a/doc/join.md
+++ b/doc/join.md
@@ -10,7 +10,7 @@ Join To connects its two arguments together, for example to join two strings:
"abcd" ∾ "EFG"
-If the arguments have the same rank, then they are combined along the first axis: the result is an array whose major cells are the major cells of `𝕨` followed by the major cells of `𝕩`. For arrays with rank two or more, this means they will be joined "vertically" according to BQN's display.
+If the arguments have the same rank, then they are combined along the first axis: the result is an array whose [major cells](array.md#cells) are the major cells of `𝕨` followed by the major cells of `𝕩`. For arrays with rank two or more, this means they will be joined "vertically" according to BQN's [display](arrayrepr.md#array-display).
⊢ a ← 3 +⌜○↕ 4
⊢ b ← 2‿4 ⥊ ↕8
@@ -42,13 +42,15 @@ To join with a separator in between, we might prepend the separator to each stri
1↓∾' '∾¨"time"‿"to"‿"join"‿"some"‿"words"
+ ∾1↓⥊(<" * ")≍˘"time"‿"to"‿"join"‿"some"‿"words"
+
Join also extends the rank of a unit element (including an atom) to allow it to fit into the list. The highest-rank element determines the rank of the result.
∾"abc"‿'d'‿"ef"‿(<'g')
∾"abcd" # Result has to be rank 0, impossible
-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.
+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.
⊢ m ← (3‿1≍⌜4‿2‿5) ⥊¨ 2‿3⥊↕6
∾ m # Join all that together