From 29509cedb9af2715328e44c481738a9ba05cff73 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 3 Nov 2021 15:51:15 -0400 Subject: =?UTF-8?q?Use=20=E2=8B=88=20rather=20than=20=E2=89=8D=E2=97=8BAbove we start with a list of three empty arrays. After merging once we get a shape 30 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 units

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 differs from Couple in this one case, as it will add an axis to get a shape 21 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.

-↗️
    2,3 < "abc"  # Pair two values
-⟨ ⟨ 2 3 ⟩ "abc" ⟩
-    < "abc"        # Pair one(?) value
-⟨ "abc" ⟩
-
+

The function Pair () can be written <, while in either valence is >. As an interesting consequence, ←→ ><, and ←→ ><. These two identities have the same form because adding < commutes with adding >.

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 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 𝕨Fk𝕩 ←→ >(<j𝕨)F¨(<k𝕩).

diff --git a/docs/doc/fold.html b/docs/doc/fold.html index b9dddf8b..f1dc9a59 100644 --- a/docs/doc/fold.html +++ b/docs/doc/fold.html @@ -134,15 +134,15 @@

Right-to-left

The functions we've shown so far are associative (ignoring floating point imprecision), meaning it's equally valid to combine elements of the argument list in any order. But it can be useful to fold using a non-associative function. In this case you must know that Fold performs a right fold, starting from the end of the array and working towards the beginning.

-↗️
    <´ "abcd"
+↗️
    ´ "abcd"
 ⟨ 'a' ⟨ 'b' "cd" ⟩ ⟩
 
-    'a' < 'b' < 'c' < 'd'  # Expanded form
+    'a'  'b'  'c'  'd'  # Expanded form
 ⟨ 'a' ⟨ 'b' "cd" ⟩ ⟩
 
-

Using the pair function < as an operand shows the structure nicely. This fold first pairs the final two characters 'c' and 'd', then pairs 'b' with that and so on. This matches BQN's right-to-left order of evaluation. More declaratively we might say that each character is paired with the result of folding over everything to its right.

+

Using Pair () as an operand shows the structure nicely. This fold first pairs the final two characters 'c' and 'd', then pairs 'b' with that and so on. This matches BQN's right-to-left order of evaluation. More declaratively we might say that each character is paired with the result of folding over everything to its right.

BQN doesn't provide a left Fold (` is Scan). However, you can fold from the left by reversing () the argument list and also reversing (˜) the operand function's argument order.

-↗️
    <˜´  "abcd"
+↗️
    ˜´  "abcd"
 ⟨ ⟨ "ab" 'c' ⟩ 'd' ⟩
 

One consequence of this ordering is that folding with Minus (-) gives an alternating sum, where the first value is added, the second subtracted, the third added, and so on. Similarly, ÷ gives an alternating product, with some elements multiplied and some divided.

@@ -151,7 +151,7 @@

The operand +÷ is a quick way to compute a continued fraction's value from a list of numbers. Here are a few terms from the continued fraction for e.

↗️
    +÷´ 21211411
-2.7183098591549295
+2.71830985915493
 

Initial element

When the operand isn't just an arithmetic primitive, folding with no initial element can be dangerous. Even if you know 𝕩 isn't empty, saving you from an "Identity not found" error, the case with only one element can easily violate expectations. Here's a somewhat silly example of a function meant to merge elements of the argument into a single list (∾⥊¨ is a much better way to do this):

@@ -206,7 +206,7 @@ ⟨ 0 0 0 0 ⟩

Just like Fold, Insert allows an initial element for the left argument, so that you don't need to rely on the interpreter knowing the identity. A more complete translation into Fold is therefore {𝕨𝔽´<˘𝕩}. The expression below shows that the operand function is called on the last major cell when the identity, then the next-to-last major cell and so on. In total there are 𝕩 calls, while there would be 1-˜𝕩 without the left argument.

-↗️
    "id" <˝ "row0 ""row1 ""row2 "
+↗️
    "id" ˝ "row0 ""row1 ""row2 "
 ┌─                                      
 · "row0 " ⟨ "row1 " ⟨ "row2 " "id" ⟩ ⟩  
                                        ┘
diff --git a/docs/doc/reverse.html b/docs/doc/reverse.html
index 6c306214..49d52f50 100644
--- a/docs/doc/reverse.html
+++ b/docs/doc/reverse.html
@@ -31,11 +31,11 @@ ERROR
   fe" 
      ┘
 
-

Reverse is useful for folding left to right instead of right to left.

-↗️
    < ´   "abcd"  # Right to left
+

Reverse is useful for folding left to right instead of right to left (here we use Pair to show structure).

+↗️
     ´   "abcd"  # Right to left
 ⟨ 'a' ⟨ 'b' "cd" ⟩ ⟩
 
-    <˜´  "abcd"  # Left to right
+    ˜´  "abcd"  # Left to right
 ⟨ ⟨ "ab" 'c' ⟩ 'd' ⟩
 

Reverse is its own inverse . As a result, 𝔽 reverses the argument, applies 𝔽, and reverses again. It's a particularly useful pattern with Scan, as it allows scanning from the end rather than the beginning of the array. For example, ` on a list of booleans changes all bits after the first 1 to 1, but ` does this to all bits before the last 1.

@@ -47,10 +47,10 @@ ERROR

Rotate

Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number for 𝕨. It has to be an integer, and 𝕩 has to be an array with at least one axis.

-↗️
    2  "rotate"
+↗️
    2  "rotate"
 "tatero"
 
-    2 ( < ) 52"rotateCELL"
+    2 (  ) 52"rotateCELL"
 ┌─               
 · ┌─     ┌─      
   ╵"ro   ╵"te    
diff --git a/docs/doc/transpose.html b/docs/doc/transpose.html
index b2319106..1cf882dc 100644
--- a/docs/doc/transpose.html
+++ b/docs/doc/transpose.html
@@ -37,8 +37,8 @@
 ⟨ 3 4 5 6 2 ⟩
 

In terms of the argument data as given by Deshape (), this looks like a simple 2-dimensional transpose: one axis is exchanged with a compound axis made up of the other axes. Here we transpose a rank 3 matrix:

-↗️
    a322  322⥊↕12
-    < a322
+↗️
    a322  322⥊↕12
+     a322
 ┌─                      
 · ┌─        ┌─          
   ╎  0  1   ╎ 0 4  8    
@@ -53,7 +53,7 @@
                        ┘
 

But, ignoring the whitespace and going in reading order, the argument and result have exactly the same element ordering as for the rank 2 matrix ˘ a322:

-↗️
    < ˘ a322
+↗️
     ˘ a322
 ┌─                          
 · ┌─            ┌─          
   ╵ 0 1  2  3   ╵ 0 4  8    
-- 
cgit v1.2.3