From 7bf2aa4054b8378a76dff63acdccbcdad91f68e6 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Sat, 7 Aug 2021 20:41:31 -0400 Subject: BREAKING: Don't allow First of empty or reshaping empty to non-empty --- docs/doc/fill.html | 21 +++++++++------------ docs/doc/find.html | 6 +++--- docs/doc/pick.html | 13 +++++-------- docs/doc/reshape.html | 8 ++++---- docs/doc/types.html | 2 +- 5 files changed, 22 insertions(+), 28 deletions(-) (limited to 'docs/doc') diff --git a/docs/doc/fill.html b/docs/doc/fill.html index 5ef9baf1..843e80e8 100644 --- a/docs/doc/fill.html +++ b/docs/doc/fill.html @@ -6,7 +6,7 @@

Fill elements

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 (↑) when a value in 𝕨 is larger than the corresponding length in 𝕩, by the two Nudge functions (»«) when 𝕩 is non-empty, and by First (βŠ‘) and Reshape (β₯Š) when 𝕩 is empty. Except for these specific cases, the fill value an array has can't affect the program. The result of Match (≑) doesn't depend on fills, and any attempt to compute a fill can't cause side effects.

+

Fills are used by Take (↑) when a value in 𝕨 is larger than the corresponding length in 𝕩, by the two Nudge functions (»«) when 𝕩 is non-empty, and by Reshape (β₯Š) when 𝕨 contains ↑. Except for these specific cases, the fill value an array has can't affect the program. The result of Match (≑) 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).

Take (↑) and Nudge (»«) 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 ≒𝕩.

@@ -26,18 +26,15 @@ »⟨⟩ # Fill not needed ⟨⟩ -

First (βŠ‘) and Reshape (β₯Š) use the fill when 𝕩 is empty, and in the case of Reshape only when the result needs to be non-empty.

-↗️
    βŠ‘ ""
-' '
-
-    4 β₯ŠΒ¨ βŸ¨β†•0, ""⟩
-⟨ ⟨ 0 0 0 0 ⟩ "    " ⟩
-
-    0β€Ώ3 β₯Š ⟨⟩  # Fill not needed
-↕0β€Ώ3
+

Reshape (β₯Š) uses the fill when 𝕨 contains ↑ and the product of the rest of 𝕨 doesn't evenly divide the number of elements in 𝕩.

+↗️
    ↑‿8 β₯Š "completepart"
+β”Œβ”€          
+β•΅"complete  
+  part    " 
+           β”˜
 
-

If for some reason you need to find an array's fill element, the easiest way is βŠ‘0β₯Ša.

-↗️
    βŠ‘0β₯Š"string"
+

If for some reason you need to find an array's fill element, the easiest general way is probably βŠ‘Β»1↑β₯Ša.

+↗️
    βŠ‘Β»1↑β₯Š"string"
 ' '
 

How fills are computed

diff --git a/docs/doc/find.html b/docs/doc/find.html index bc883db2..1421500e 100644 --- a/docs/doc/find.html +++ b/docs/doc/find.html @@ -32,14 +32,14 @@ "string" (β‰’βˆ˜βŠ’β†‘β·) "substring" # APL style ⟨ 0 0 0 1 0 0 0 0 0 ⟩
-

If 𝕨 is larger than 𝕩, the result is empty, and there's no error even in cases where Windows would fail. One place this tends to come up is when applying First (βŠ‘) the result: βŠ‘β· tests whether 𝕨 appears in 𝕩 at the first position, that is, whether it's a prefix of 𝕩. If 𝕨 is longer than 𝕩 it shouldn't be a prefix, so 0 is appropriate.

-↗️
    "loooooong" ⍷ "short"
+

If 𝕨 is larger than 𝕩, the result is empty, and there's no error even in cases where Windows would fail. One place this tends to come up is when applying First (βŠ‘) the result: βŠ‘β· tests whether 𝕨 appears in 𝕩 at the first position, that is, whether it's a prefix of 𝕩. If 𝕨 is longer than 𝕩 it shouldn't be a prefix. First will fail but using a fold 0⊣´β₯Šβˆ˜β· instead gives a 0 in this case.

+↗️
    "loooooong" ⍷ "short"
 ⟨⟩
 
     9 ↕ "short"
 ERROR
 
-    βŠ‘ "loooooong" ⍷ "short"
+    0 ⊣´ "loooooong" ⍷ "short"
 0
 

This pattern also works in the high-rank case discussed below, testing whether 𝕨 is a multi-dimensional prefix starting at the lowest-index corner of 𝕩.

diff --git a/docs/doc/pick.html b/docs/doc/pick.html index b0e99195..a296d6c0 100644 --- a/docs/doc/pick.html +++ b/docs/doc/pick.html @@ -6,7 +6,7 @@

Pick

Pick (βŠ‘) chooses elements from 𝕩 based on index lists from 𝕨. 𝕨 can be a plain list, or even one number if 𝕩 is a list, in order to get one element from 𝕩. It can also be an array of index lists, or have deeper array structure: each index list will be replaced with the element of 𝕩 at that index, effectively applying to 𝕨 at depth 1.

-

With no 𝕨, monadic βŠ‘π•© takes the first element of 𝕩 in index order, or its fill element if 𝕩 is empty (causing an error if no fill is known).

+

With no 𝕨, monadic βŠ‘π•© takes the first element of 𝕩 in index order, with an error if 𝕩 is empty.

While sometimes "scatter-point" indexing is necessary, using Pick to select multiple elements from 𝕩 is less array-oriented than Select (⊏), and probably slower. Consider rearranging your data so that you can select along axes instead of picking out elements.

One element

When the left argument is a number, Pick gets an element from a list:

@@ -55,15 +55,12 @@ βŠ‘ ↕4β€Ώ2β€Ώ5β€Ώ1 ⟨ 0 0 0 0 ⟩
-

If 𝕩 is empty then Pick always results in an error. First never gives an error: instead it returns the fill element for 𝕩.

-↗️
    βŠ‘ ""
-' '
+

If 𝕩 is empty then First results in an error, like Pick.

+↗️
    βŠ‘ ""
+ERROR
     βŠ‘ β‰’Ο€
-0
-    βŠ‘ 0↑<⟨"  ",↕4⟩
-⟨ "  " ⟨ 0 0 0 0 ⟩ ⟩
+ERROR
 
-

So one way to find the fill element for an array 𝕩 of any shape is βŠ‘0β₯Šπ•©.

In APL it's common to get the last element of a list with an idiom that translates to βŠ‘βŒ½, or First-Reverse. In BQN the most straightforward way is to select with index Β―1 instead. I also sometimes use Fold with the Right identity function.

↗️
    βŠ‘βŒ½ "last"
 't'
diff --git a/docs/doc/reshape.html b/docs/doc/reshape.html
index 23e77e9c..b9d16cc5 100644
--- a/docs/doc/reshape.html
+++ b/docs/doc/reshape.html
@@ -142,12 +142,12 @@
   235 236 237  
               β”˜
 
-

If the left argument implies a larger number of elements, then the argument elements are reused cyclically. Below, we reach the last element 247 and start over at 135. If the array doesn't have any elements to start with, its fill element is used instead, but it's probably best not to invoke this case!

-↗️
    15 β₯Š a
+

If the left argument implies a larger number of elements, then the argument elements are reused cyclically. Below, we reach the last element 247 and start over at 135. If the array doesn't have any elements to start with, you'll get an error as there aren't any elements available.

+↗️
    15 β₯Š a
 ⟨ 135 136 137 145 146 147 235 236 237 245 246 247 135 136 137 ⟩
 
-    4 β₯Š ↕0  # Fill for ↕0 is 0
-⟨ 0 0 0 0 ⟩
+    4 β₯Š ↕0
+ERROR
 

Reshape is the idiomatic way to make an array filled with a constant value (that is, where all elements are the same). For an atom element, just reshape it directly; for an arbitrary element, first enclose it to create a unit, and then reshape it.

↗️
    3β€Ώ4 β₯Š 0
diff --git a/docs/doc/types.html b/docs/doc/types.html
index 46356766..bcc119f6 100644
--- a/docs/doc/types.html
+++ b/docs/doc/types.html
@@ -59,7 +59,7 @@
 

Arrays

Full documentation here.

A BQN array is a multidimensional arrangement of data. This means it has a certain shape, which is a finite list of natural numbers giving the length along each axis, and it contains an element for each possible index, which is a choice of one natural number that's less than each axis length in the shape. The total number of elements, or bound, is then the product of all the lengths in the shape. The shape may have any length including zero, and this shape is known as the array's rank. An array of rank 0, which always contains exactly one element, is called a unit, while an array of rank 1 is called a list and an array of rank 2 is called a table.

-

Each arrayβ€”empty or nonemptyβ€”has an inferred property called a fill. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills can be used by Take (↑), the two Nudge functions (»«), First (βŠ‘), and Reshape (β₯Š).

+

Each arrayβ€”empty or nonemptyβ€”has an inferred property called a fill. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills can be used by Take (↑), the two Nudge functions (»«), and Reshape (β₯Š).

Arrays are value types (or immutable), so that there is no way to "change" the shape or elements of an array. An array with different properties is a different array. As a consequence, arrays are an inductive type, and it's not possible for an array to contain itself, or contain an array that contains itself, and so on. However, it is possible for an array to contain a function or other operation that has access to the array through a variable, and in this sense an array can "know about" itself.

Different elements of an array should not influence each other. While some APLs force numbers placed in the same array to a common representation, which may have different precision properties, BQN values must not change behavior when placed in an array. However, this doesn't preclude changing the storage type of an array for better performance: for example, in a BQN implementation using 64-bit floats, an array whose elements are all integers that fit in 32-bit int range might be represented as an array of 32-bit ints.

Operation types

-- cgit v1.2.3