From c3ea468236e362e4ecc1bc27aed7a64d90e7cf81 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Thu, 2 Jun 2022 21:42:44 -0400 Subject: Always use "index list", not "list index", for a full element index --- doc/glossary.md | 1 + doc/identity.md | 2 +- doc/indices.md | 10 +++++----- doc/pick.md | 2 +- doc/range.md | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) (limited to 'doc') diff --git a/doc/glossary.md b/doc/glossary.md index e677c739..7f8d4bf4 100644 --- a/doc/glossary.md +++ b/doc/glossary.md @@ -67,6 +67,7 @@ The possible roles are: * **Table**: An array of rank 2. * [**Index**](indices.md): One of a variety of ways to select an element, cell, axis, or position along an axis of an array. +* [**Index list**](indices.md#element-indices): A list of numbers indicating a single element of an array. ## Operations diff --git a/doc/identity.md b/doc/identity.md index 648fe466..d310610b 100644 --- a/doc/identity.md +++ b/doc/identity.md @@ -53,6 +53,6 @@ A larger class of block functions can be translated just by adding parentheses a ## One more thing -You've probably seen `⊢` used in documentation to display the value of a variable being assigned. This is a hack, and in most contexts `•Show` should be used to display values. +You've probably seen `⊢` used in documentation to display the value of a variable being assigned. Normally `•Show` is used to display values, but the website is sort of a weird context: it displays by default but disables it if the final thing done is an assignment. `⊢` isn't assignment, so it works arround that rule. ⊢ a ← "show this" diff --git a/doc/indices.md b/doc/indices.md index b2bff7cd..b2db1603 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. 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](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 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](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. @@ -24,15 +24,15 @@ In [Reorder Axes](transpose.md#reorder-axes) (`⍉`), `𝕨` is made up of indic ## Element indices -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. +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 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 `/` 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 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. -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 [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 `𝕨`. 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? ## 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 list indices. 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 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. [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. diff --git a/doc/pick.md b/doc/pick.md index 092f87ed..254c64ec 100644 --- a/doc/pick.md +++ b/doc/pick.md @@ -63,7 +63,7 @@ Pick also accepts a list of indices: ⟨2‿0, 1‿¯1, 3‿1, ¯1‿¯1⟩ ⊑ a -These indices have to be lists, since if they're numbers it just looks like `𝕨` is one list index. +These indices have to be lists, since if they're numbers it just looks like `𝕨` is an index list for one element. ⟨2,1,0,¯1⟩ ⊑ "abc" # 𝕩 doesn't have rank 4! diff --git a/doc/range.md b/doc/range.md index 60e1afbb..40464bbf 100644 --- a/doc/range.md +++ b/doc/range.md @@ -8,7 +8,7 @@ Range (`↕`) is a monadic function that creates arrays of [indices](indices.md) ↕ 2‿3 -It's really two different functions packed together: if `𝕩` is a natural number—a length—then it returns a list of numeric indices, but if it's a list of numbers, then it returns an array of list indices. This means the result always has [depth](depth.md) one more than the argument. +It's really two different functions packed together: if `𝕩` is a natural number—a length—then it returns a list of numeric indices, but if it's a list of numbers, then it returns an array of index lists. This means the result always has [depth](depth.md) one more than the argument. The two kinds of index correspond to BQN's two selection functions: [Select](select.md) (`⊏`) works with indices along an axis, which are numbers, and [Pick](pick.md) (`⊑`) works with element indices, which are lists. The examples below would fail if we swapped these around. Each result from Range is a length-6 list, but their elements are different. -- cgit v1.2.3