From e2b07a5fd0bbaad232c717fb90a31d6c61d72bd4 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Thu, 14 Jul 2022 20:06:50 -0400 Subject: Try to include previous variable definitions in REPL links --- docs/doc/block.html | 8 ++++---- docs/doc/constant.html | 2 +- docs/doc/couple.html | 2 +- docs/doc/depth.html | 4 ++-- docs/doc/expression.html | 2 +- docs/doc/find.html | 2 +- docs/doc/fold.html | 4 ++-- docs/doc/functional.html | 12 ++++++------ docs/doc/group.html | 8 ++++---- docs/doc/join.html | 4 ++-- docs/doc/leading.html | 10 +++++----- docs/doc/lexical.html | 10 +++++----- docs/doc/match.html | 6 +++--- docs/doc/oop.html | 2 +- docs/doc/order.html | 6 +++--- docs/doc/pick.html | 6 +++--- docs/doc/quick.html | 20 ++++++++++---------- docs/doc/range.html | 4 ++-- docs/doc/rank.html | 16 ++++++++-------- docs/doc/rebqn.html | 8 ++++---- docs/doc/replicate.html | 8 ++++---- docs/doc/reshape.html | 8 ++++---- docs/doc/reverse.html | 4 ++-- docs/doc/scan.html | 2 +- docs/doc/search.html | 8 ++++---- docs/doc/select.html | 2 +- docs/doc/selfcmp.html | 2 +- docs/doc/shape.html | 2 +- docs/doc/shift.html | 8 ++++---- docs/doc/take.html | 2 +- docs/doc/train.html | 6 +++--- docs/doc/transpose.html | 20 ++++++++++---------- docs/doc/under.html | 2 +- docs/help/change.html | 4 ++-- docs/tutorial/variable.html | 22 +++++++++++----------- md.bqn | 29 ++++++++++++++++++++++++++++- 36 files changed, 146 insertions(+), 119 deletions(-) diff --git a/docs/doc/block.html b/docs/doc/block.html index ec9e4ed9..cfffe895 100644 --- a/docs/doc/block.html +++ b/docs/doc/block.html @@ -176,7 +176,7 @@

Unlike these assignments, the header also constrains what inputs the block can take: a monadic 1-modifier like the one above can't take a right operand or left argument, so its body can't contain 𝔾 or 𝕨. Calling it with a left argument, or a right argument that isn't a two-element list, will result in an error.

Destructuring

Arguments and operands allow destructuring like assignment does. While assignment only tolerates lists of variables, header destructuring also allows constants. For the header to match, the argument must share the given structure, including the constants where they appear.

-↗️
    Destruct  { 𝕊 a1b,·,2: ab }
+↗️
    Destruct  { 𝕊 a1b,·,2: ab }
     Destruct       517,π,2
 ⟨ 5 7 ⟩
 
@@ -219,12 +219,12 @@ ⟨ 2 4 ⟩

If no header is compatible, the call results in an error.

-↗️
    3 CaseAdd 3
+↗️
    3 CaseAdd 3
 Error: No header matched arguments
 

Case headers

A special rule allows for convenient case-matching syntax for one-argument functions. In any function header with one argument, the function name can be omitted as long as the argument is not a plain identifier—it must be 𝕩 or a compound value like a list to distinguish it from an immediate block label.

-↗️
    Test  {
+↗️
    Test  {
       "abc": "string" ;
       2,b: 𝕩       ;
       5:     "number" ;
@@ -236,7 +236,7 @@
 

These case-style headers function exactly the same as if they were preceded by 𝕊, and can be mixed with other kinds of headers.

Predicates

Destructuring with a header is limited, as it can only match a particular structure or value exactly—not, for example, a range of lengths. A predicate, written with ?, allows you to test an arbitrary property before evaluating the rest of the body, and also serves as a limited kind of control flow. It can be thought of as an extension to a header. So the following function requires the argument to have two elements and for the first to be less than the second before using the first body. Otherwise it moves to the next body, which is unconditional.

-↗️
    CheckPair  { 𝕊a,b: a<b? "ok" ; "not ok" }
+↗️
    CheckPair  { 𝕊a,b: a<b? "ok" ; "not ok" }
 
     CheckPair 3,8    # Fails destructuring
 "ok"
diff --git a/docs/doc/constant.html b/docs/doc/constant.html
index d68235aa..258ae26b 100644
--- a/docs/doc/constant.html
+++ b/docs/doc/constant.html
@@ -50,6 +50,6 @@
 ⟨ 1 2 ¯3 4 ⟩
 

Here m is applied to 2𝕩 even though we want to discard that value. Spelled as m, our context-free grammar knows it's a function argument, but this doesn't affect later usage. Under always applies 𝔽 as a function. The proper definition of the insertion function should use a ˙, like this:

-↗️
    m {𝕨˙(2) 𝕩} 1234
+↗️
    m {𝕨˙(2) 𝕩} 1234
 ⟨ 1 2 - 4 ⟩
 
diff --git a/docs/doc/couple.html b/docs/doc/couple.html index 86d8434a..e583b7f6 100644 --- a/docs/doc/couple.html +++ b/docs/doc/couple.html @@ -66,7 +66,7 @@

As a consequence, Pair () can be written <, while is > as discussed above. This gives the neat (but not useful) identities ←→ ><, and ←→ ><, which have the same form because adding < commutes with adding >.

Merge and array theory

In all cases, what these functions do is more like reinterpreting existing data than creating new information. In fact, if we ignore the shape and look at the deshaped arrays involved in a call to Merge, we find that it just joins them together. Essentially, Merge is a request to ensure that the inner arrays make up a homogeneous (not "ragged") array, and then to consider them to be such an array. It's the same thing Rank does to combine the result cells from its operand into a single array.

-↗️
     > a
+↗️
     > a
 "ABrstABuvwABxyzCDrstCDuvwCDxyz"
 
      ¨ a
diff --git a/docs/doc/depth.html b/docs/doc/depth.html
index 596faa33..7bce4e89 100644
--- a/docs/doc/depth.html
+++ b/docs/doc/depth.html
@@ -162,7 +162,7 @@
 3
 

Reversing n swaps all the rows:

-↗️
     n
+↗️
     n
 ┌─                                                             
 ╵ ⟨ ⟨ 36 37 38 ⟩ ⟨ 39 40 41 ⟩ ⟩ ⟨ ⟨ 42 43 44 ⟩ ⟨ 45 46 47 ⟩ ⟩  
   ⟨ ⟨ 24 25 26 ⟩ ⟨ 27 28 29 ⟩ ⟩ ⟨ ⟨ 30 31 32 ⟩ ⟨ 33 34 35 ⟩ ⟩  
@@ -171,7 +171,7 @@
                                                               ┘
 

Depth ¯1 is equivalent to Each, and reverses the larger lists, while depth ¯2 applies Each twice to reverse the smaller lists:

-↗️
    ¯1 n
+↗️
    ¯1 n
 ┌─                                                             
 ╵ ⟨ ⟨ 3 4 5 ⟩ ⟨ 0 1 2 ⟩ ⟩       ⟨ ⟨ 9 10 11 ⟩ ⟨ 6 7 8 ⟩ ⟩      
   ⟨ ⟨ 15 16 17 ⟩ ⟨ 12 13 14 ⟩ ⟩ ⟨ ⟨ 21 22 23 ⟩ ⟨ 18 19 20 ⟩ ⟩  
diff --git a/docs/doc/expression.html b/docs/doc/expression.html
index b8f9254c..f8c40256 100644
--- a/docs/doc/expression.html
+++ b/docs/doc/expression.html
@@ -234,7 +234,7 @@
 ⟨ ⟨ 1 0 ⟩ ⟨ 1 1 ⟩ ⟨ 1 2 ⟩ ⟩
 

Namespace destructuring uses an overlapping syntax, fully described in its own section. The left hand side is a list of names, or aliases tofrom.

-↗️
    qr  {q2+r0.5}  q
+↗️
    qr  {q2+r0.5}  q
 2.5
 

With destructuring, you might want to discard some values from the right hand side rather than assign them any name. There's special syntax for this: use Nothing (·) for a placeholder non-name in the appropriate position, like ·y· list.

diff --git a/docs/doc/find.html b/docs/doc/find.html index 01efff6d..7d30ff18 100644 --- a/docs/doc/find.html +++ b/docs/doc/find.html @@ -67,7 +67,7 @@ ┘

It's also allowed for 𝕨 to have a smaller rank than 𝕩; the axes of 𝕨 then correspond to trailing axes of 𝕩, so that leading axes of 𝕩 are mapped over. This is a minor violation of the leading axis principle, which would match axes of 𝕨 to leading axes of 𝕩 in order to make a function that's useful with the Rank operator, but such a function would be quite strange and hardly ever useful.

-↗️
    0101  a
+↗️
    0101  a
 ┌─             
 ╵ 0 0 0 0 0 0  
   0 0 0 0 0 0  
diff --git a/docs/doc/fold.html b/docs/doc/fold.html
index 5b024ff4..d59caf97 100644
--- a/docs/doc/fold.html
+++ b/docs/doc/fold.html
@@ -195,7 +195,7 @@
 ⟨ 9 7 12 ⟩
 

The Insert (˝) modifier will do this for you. And because it works on the leading axis of the argument, Insert can be applied to axes other than the first with Rank. Sum each row (second axis) with Cells (˘), for example.

-↗️
    +˝˘ tab
+↗️
    +˝˘ tab
 ⟨ 2 3 6 5 12 ⟩
 

This case is tricky, because +´˘ tab yields the same result but is actually unsound—if tab contains arrays then they will be merged together at the end. Remember: if you want to reduce along one axis of an array and get an array of results out, you should use Insert (possibly adding Each to work on elements instead of cells; see APL2 reduction below).

@@ -243,7 +243,7 @@

As a historical note, Insert is named after J's adverb /, which comes from SHARP APL's , reduce-down. In the original APL, only arithmetic reductions were defined, and nested arrays didn't exist—arrays were either all characters or all numbers. SHARP extended them by splitting the array into cells as we've shown. However, there's another interpretation, which is what you'll find in mainstream APLs today…

APL2 reduction?

The function ⍪⌿ in Dyalog APL gives very different results from BQN's ˝. Instead of combining the cells like we see above, APL applies the function on pairs of elements much like Fold. The difference is that, because reduction happens only along one axis but an array might have other axes, there can be multiple values in the result, so that it will always be an array like the argument. BQN can perform this operation as well: ⍪⌿ is written ¨˝ in BQN (but please use <˘ instead).

-↗️
    tab
+↗️
    tab
 ┌─       
 ╵ 1 0 1  
   0 1 2  
diff --git a/docs/doc/functional.html b/docs/doc/functional.html
index f3eea496..bec89fee 100644
--- a/docs/doc/functional.html
+++ b/docs/doc/functional.html
@@ -76,31 +76,31 @@
     }
 

We can pass it the exponential function as an argument by giving it the name Exp and then referring to it in lowercase (that is, in a subject role). The result is a train that adds 1 to e-1 times the argument (we'll discuss only tacit functions here; for blocks see lexical scoping).

-↗️
    Exp  
+↗️
    Exp  
     Lin exp
 1+1.718281828459045×⊢
 

As with all functions, the result of Lin has a subject role. To use it as a function, we give it a name and then use that name with an uppercase spelling.

-↗️
    expLin  Lin exp
+↗️
    expLin  Lin exp
     ExpLin 5
 9.591409142295225
 

A tricker but more compact method is to use the 1-modifier {𝔽}, as a modifier's operand can have a subject or function role but its output always has a function role.

-↗️
    (Lin exp){𝔽} 5
+↗️
    (Lin exp){𝔽} 5
 9.591409142295225
 

Not the most accurate approximation, though.

-↗️
    Exp 5
+↗️
    Exp 5
 148.4131591025766
 

Note also in this case that we could have used a modifier with a very similar definition to Lin. The modifier is identical in definition except that 𝕏 is replaced with 𝔽.

-↗️
    _lin  {
+↗️
    _lin  {
       v0  𝔽 0
       v0 + ((𝔽 1) - v0) × 
     }
 

Its call syntax is simpler as well. In other cases, however, the function version might be preferable, for example when dealing with arrays of functions or many arguments including a function.

-↗️
    Exp _lin 5
+↗️
    Exp _lin 5
 9.591409142295225
 

Arrays of functions

diff --git a/docs/doc/group.html b/docs/doc/group.html index d9b16bb2..b2227519 100644 --- a/docs/doc/group.html +++ b/docs/doc/group.html @@ -76,7 +76,7 @@

(Could we define phrase more easily? See below.)

If we'd like to ignore words of 0 letters, or more than 5, we can set all word lengths greater than 5 to 0, then reduce the lengths by 1. Two words end up with left argument values of ¯1 and are omitted from the result.

-↗️
    1 -˜ 5× ¨ phrase
+↗️
    1 -˜ 5× ¨ phrase
 ⟨ 2 3 ¯1 1 0 3 1 ¯1 ⟩
 
     ˘ {1-˜5×≠¨𝕩} phrase
@@ -88,7 +88,7 @@
                     ┘
 

Note that the length of the result is determined by the largest index. So the result never includes trailing empty groups. A reader of the above code might expect 5 groups (lengths 1 through 5), but there are no words of length 5, so the last group isn't there. To ensure the result always has 5 groups, we can add a 5 at the end of the left argument.

-↗️
    ˘ {5˜1-˜5×≠¨𝕩} phrase
+↗️
    ˘ {5˜1-˜5×≠¨𝕩} phrase
 ┌─                   
 ╵ ⟨ "a" ⟩            
   ⟨ "as" "of" ⟩      
@@ -137,7 +137,7 @@
                              ┘
 

If we would like a particular index to key correspondence, we can use a fixed left argument to Index Of.

-↗️
    countries  "IT""JP""NO""SU""US"
+↗️
    countries  "IT""JP""NO""SU""US"
     countries ˘ co countries ln
 ┌─                                 
 ╵ "IT" ⟨⟩                          
@@ -148,7 +148,7 @@
                                   ┘
 

However, this solution will fail if there are trailing keys with no values. To force the result to have a particular length you can append that length to the left argument.

-↗️
    countries  "IT""JP""NO""SU""US""ZW"
+↗️
    countries  "IT""JP""NO""SU""US""ZW"
     countries ˘ co countries(⊐∾≠) ln
 ┌─                                 
 ╵ "IT" ⟨⟩                          
diff --git a/docs/doc/join.html b/docs/doc/join.html
index e2876a74..b0f9ead4 100644
--- a/docs/doc/join.html
+++ b/docs/doc/join.html
@@ -33,11 +33,11 @@
           ┘
 

For this definition to work, major cells of 𝕨 and 𝕩 have to have the same shape. That means that 𝕨(1↓≢)𝕩, and the shape of the result is the sum of the lengths of 𝕨 and 𝕩 followed by their shared major cell shape: to use a self-referential definition, the final shape is given by + (1↓≢) for arguments of equal rank.

-↗️
    a  25b  # Shapes don't fit
+↗️
    a  25b  # Shapes don't fit
 Error: ∾: Lengths not matchable (3‿4 ≡ ≢𝕨, 2‿5 ≡ ≢𝕩)
 

Join To will also allow arguments with ranks that are one apart. In this case, the smaller-rank argument is treated as a major cell in its entirety. If for example 𝕨<=𝕩, then we must have (𝕨)1↓≢𝕩, and the result shape is 1+⊑≢𝕩.

-↗️
    4230  a
+↗️
    4230  a
 ┌─         
 ╵ 4 2 3 0  
   0 1 2 3  
diff --git a/docs/doc/leading.html b/docs/doc/leading.html
index b3b008c8..63cdc85f 100644
--- a/docs/doc/leading.html
+++ b/docs/doc/leading.html
@@ -34,7 +34,7 @@
      ┘
 

To use these functions on another axis, use the Rank () or Cells (˘) modifier to find the one you want. For a rank 2 array like a, the most you'll ever need is a single ˘, because after the leading one there's only one other axis.

-↗️
    ˘ a                  # First column
+↗️
    ˘ a                  # First column
 "ace"
 
     ˘ a                  # Swap the columns
@@ -52,7 +52,7 @@
      ┘
 

In these three cases above, the results are the same as you would get from transposing before and after (which does nothing to the rank-1 result of ˘, but that's what's wanted). But in the following cases, the structure is quite different: a is a list of matrices while ˘a is a matrix of lists. This is because the functions , , and ` leave the trailing axis structure intact ( removes one axis); taking into account that Rank or Cells always preserves the leading or frame axes, all axes are preserved (except the one removed by ). But Prefixes or Suffixes move axes after the first from the whole of 𝕩 to elements of the result, pushing them down in depth, and Rank won't undo this sort of structural change.

-↗️
     a                   # Prefixes of a:    ranks 1|2
+↗️
     a                   # Prefixes of a:    ranks 1|2
 ┌─                           
 · ↕0‿2 ┌─     ┌─     ┌─      
        ╵"ab"  ╵"ab   ╵"ab    
@@ -79,7 +79,7 @@
      ┘
 

Solo (), something of a maverick, manages to act on zero leading axes of 𝕩 by creating the first axis of the result instead. Because it doesn't need any axis to work, it can go in front of either axis but also past the last one by working with rank 0, a case where most array functions would give an error.

-↗️
      a                 # Solo adds a length-1 axis
+↗️
      a                 # Solo adds a length-1 axis
 ⟨ 1 3 2 ⟩
 
     a    a             # First Cell undoes this
@@ -187,7 +187,7 @@
                   ┘
 

That's shape 324 matched with shape 3: the leading 3 agrees. Now to match with 32:

-↗️
     c  100 × 3 = 2  # A rank-2 array to add
+↗️
     c  100 × 3 = 2  # A rank-2 array to add
 ┌─         
 ╵ 100   0  
     0 100  
@@ -207,7 +207,7 @@
                   ┘
 

And of course, identical shapes agree:

-↗️
    x + x                 # Pairwise addition
+↗️
    x + x                 # Pairwise addition
 ┌─             
 ╎  0  2  4  6  
    8 10 12 14  
diff --git a/docs/doc/lexical.html b/docs/doc/lexical.html
index 4d34cdae..6ff7f51e 100644
--- a/docs/doc/lexical.html
+++ b/docs/doc/lexical.html
@@ -51,7 +51,7 @@
 42
 

So the Count function above increments and prints a global counter by a global amount inc, which is visible in Count because it's visible everywhere. Or, not quite… if a block defines its own copy of inc, then it will lose access to the outer one. However, code that comes before that definition can still see the outer variable. So it can copy its value at the start of the block (this won't reflect later changes to the value. Don't shadow variables you want to use!).

-↗️
    { inc3  inc }  # inc is shadowed
+↗️
    { inc3  inc }  # inc is shadowed
 3
 
     inc  # But it's still here in the outer scope
@@ -61,11 +61,11 @@
 6
 

Each scope can only define a given name once. Trying to shadow a name that's in the current scope and not a higher one gives an error at compilation.

-↗️
    { inc3  inc4 }
+↗️
    { inc3  inc4 }
 Error: Redefinition
 

Let's go all in on shadowing and make a modifier that creates its own copies of counter and inc, returning a custom version of the Count function above.

-↗️
    _makeCount  { counterinc𝕗  { counter + 𝕩 × inc } }
+↗️
    _makeCount  { counterinc𝕗  { counter + 𝕩 × inc } }
 
     C3_7  37 _makeCount  # Start at 3; inc by 7
 
@@ -90,7 +90,7 @@
 

Why define things this way? It's easier to see if you imagine the variable used is also a function. It's normal for a function to call other functions defined at the top level, of course. And it would be pretty unpleasant for BQN to enforce a specific ordering for them. It would also make recursive functions impossible except by using 𝕊, and mutually recursive ones completely impossible. A simple rule that makes all these things just work smoothly seems much better than any alternative.

Closures

Let's run _makeCount from above a few more times.

-↗️
    C4_2  42 _makeCount  # Start at 4; increment by 2
+↗️
    C4_2  42 _makeCount  # Start at 4; increment by 2
     C1_4  14 _makeCount  #          1;              4
 
     C4_2 0
@@ -139,7 +139,7 @@
 30
 

Only source code with access to a variable can modify it! This means that if none of the code in a variable's scope modifies it, then the variable is constant. That is, constant once it's defined: remember that it's still possible to get an error if the variable is accessed before being defined.

-↗️
    { { a }  a4 }
+↗️
    { { a }  a4 }
 Error: Reading variable before its defined
 

With lexical scoping, variable mutation automatically leads to mutable data. This is because a function or modifier that depends on the variable value changes its behavior when the variable changes. So do objects; this slightly more concrete case is discussed here. The behavior change is observed by calling operations, and by accessing object fields. These are the only two actions that might behave differently when applied to the same values!

diff --git a/docs/doc/match.html b/docs/doc/match.html index 767a4bb5..13568805 100644 --- a/docs/doc/match.html +++ b/docs/doc/match.html @@ -67,7 +67,7 @@ 13

(A side note is that BQN restricts what can cause these side effects: they can only happen by calling a block function or modifier, and never a primitive or purely tacit operation). Now suppose we share the value of F with another variable like F1 below. When we apply G, the result of F might change, but so does F1! This effect is called aliasing.

-↗️
    F1  F
+↗️
    F1  F
     {𝕏 6}¨ FF1
 ⟨ 14 14 ⟩
 
@@ -77,7 +77,7 @@
 ⟨ 9 9 ⟩
 

In some cases you might not be able to demonstrate aliasing so cleanly. A function such as a random number generator changes its own state, so calling one function will change the other. But comparison tells you directly whether two blocks are the same.

-↗️
    f = f1
+↗️
    f = f1
 1
 

As with other kinds of functions, just because two blocks always behave the same doesn't mean they are equal. Any function that's written as {𝕩} will always work the same as other functions spelled that way, but the two functions below are different instances because they come from two different places in the source code.

@@ -92,7 +92,7 @@ ⟨ 8 12 ⟩

These functions both have the definition {a×𝕩}, but give different results! They are different instances of the same block, and have different environments: for T2, a is 2, and for T3, it's 3.

-↗️
    t2 = t3
+↗️
    t2 = t3
 0
 

Some definitions should help to make things clearer. A "block" is not actually a BQN value, but a region of source code enclosed in {} brackets. When the program encounters a block function or modifier, it creates an instance of this block, and then uses this instance in the rest of the expression (actually, an immediate block also creates an instance, but this instance is immediately run, and discarded when it finishes, so it can't be accessed as a value). Every time the function Gen is run, it evaluates the statements it contains, and the second statement {a×𝕩} creates a block instance. So Gen creates a new block instance each time. This is necessary for Gen to work correctly: each time it runs, it creates a new scope, so it needs to create a new function that will be tied to that scope.

diff --git a/docs/doc/oop.html b/docs/doc/oop.html index 4102ddc1..093068f0 100644 --- a/docs/doc/oop.html +++ b/docs/doc/oop.html @@ -84,7 +84,7 @@

Two variables l and Transfer aren't exported, for two different reasons. l encodes the state of the tower, but it's only exposed with the function View, which allows the internal representation to be changed freely. Transfer is just a utility function. While it's not dangerous to use outside of the object, there's no reason to expose it through towerOfHanoi's interface. If it's wanted in another place it should be moved to a common location.

Here are the results of a few applications of these functions.

-↗️
    t  towerOfHanoi
+↗️
    t  towerOfHanoi
     t.View@
 ⟨ ⟨ 0 1 2 3 4 ⟩ ⟨⟩ ⟨⟩ ⟩
 
diff --git a/docs/doc/order.html b/docs/doc/order.html
index 15111965..050b6763 100644
--- a/docs/doc/order.html
+++ b/docs/doc/order.html
@@ -79,7 +79,7 @@
 ⟨ 3 1 0 2 ⟩
 

Given our list l of things in a solar system, Sort Up orders them by size, or maybe alphabetically. What does l do? Its result also orders these items, but instead of listing them directly, each element is the index of that cell in the argument. So the way to read it is that the first item in sorted order is cell 3 of the argument, "asteroid". The second is cell 1, "moon", and the third—forget this, we made programming languages for a reason.

-↗️
    (l)  l
+↗️
    (l)  l
 ⟨ "asteroid" "moon" "planet" "star" ⟩
 

Ordinals

@@ -145,7 +145,7 @@

So the elements of the Grade of an array correspond to the cells of that array after it's sorted. It's tempting if you don't have the sorted list handy to try to match them up with major cells of the original array, but this never makes sense—there's no relationship. However, applying Grade twice gives us a list that does correspond to the original argument quite usefully: it says, for each major cell of that argument, what rank it has relative to the others (smallest is 0, next is 1, and so on, breaking ties in favor of which cell comes earlier in the argument). Experienced APL programmers call this pattern the "ordinals" idiom.

-↗️
    l  ⍋⍋ l
+↗️
    l  ⍋⍋ l
 ┌─                                   
 ╵ "planet" "moon" "star" "asteroid"  
   2        1      3      0           
@@ -176,7 +176,7 @@
              ┘
 

Here we order a table by its second column. Maybe in this case it's not a problem if "dog" and "pig" trade places. But unpredictability is never good—would you get the same results with a different implementation of BQN? And for many other applications of Grade the ordering of equal elements is important. So BQN specifies that matching cells are always ordered by their indices. The same rule applies for Grade Down, so that for example the grade in either direction of an array 𝕩 where all cells are the same is ↕≠𝕩. One effect is that 𝕩 is not always the same as ⌽⍒𝕩, even though 𝕩 always matches ⌽∨𝕩. And in the table below we can see that the numbers are all reversed but "dog" and "pig" stay in the same order.

-↗️
    (1˘t)  t
+↗️
    (1˘t)  t
 ┌─            
 ╵ "ant"    6  
   "dog"    4  
diff --git a/docs/doc/pick.html b/docs/doc/pick.html
index 060dcdc1..d6e42149 100644
--- a/docs/doc/pick.html
+++ b/docs/doc/pick.html
@@ -72,7 +72,7 @@
 

Many elements

Pick also accepts a list of indices:

-↗️
    a  # Defined above
+↗️
    a  # Defined above
 ┌─       
 ╵"abcde  
   fghij  
@@ -94,7 +94,7 @@
 "cbac"
 

It's much more general than just a list of indices though. As long as your indices are lists, you can arrange them in any array structure with arbitrary nesting.

-↗️
    20, ⟨⟨1¯1, 31, ¯1¯1⟩⟩  a
+↗️
    20, ⟨⟨1¯1, 31, ¯1¯1⟩⟩  a
 ⟨ 'k' ⟨ "jq" 't' ⟩ ⟩
 
     (20, 1¯131, ¯1¯1)  a
@@ -114,7 +114,7 @@
               ┘
 

This option is easily described using the Depth modifier. Pick applies to depth-1 components of the left argument and the entire right argument, which corresponds to a depth operand of 1. The left argument components have to be lists of numbers, or Pick gives an error.

-↗️
    (20, <1¯1<31, ¯1¯1) 1 a
+↗️
    (20, <1¯1<31, ¯1¯1) 1 a
 ┌─             
 ╵ 'k'   ┌·     
         ·'j'   
diff --git a/docs/doc/quick.html b/docs/doc/quick.html
index 3b89af8c..af70a7b7 100644
--- a/docs/doc/quick.html
+++ b/docs/doc/quick.html
@@ -62,7 +62,7 @@
 

The function Lower is defined to be -diff, but it uses a different arrow to do this. This is an export, and it declares that Lower is a field of a namespace that can be accessed from the outside. Having a in it is also what makes the block define a namespace. Lower itself won't be used for a while, but Upper is accessed a few lines down, with case.Upper.

Lower is created with a modifier again, this time the 2-modifier . We've now seen one each of the three primitive types: function, 1-modifier, and 2-modifier. There are a lot of primitives, but some simple rules tell you which type they have. Primitives are functions by default, but superscript characters are 1-modifiers (´⁼˘¨˜` in our program), and ones with an unbroken circle are 2-modifiers (⟜∘⌾; is a broken circle so it's a function). Variable names follow a similar system, where functions start with an uppercase letter and subjects with a lowercase one.

After () takes two operands, - and diff, to produce a function—specifically, it binds diff as the right argument of -, so that calling it on an argument subtracts diff from that argument.

-↗️
    -diff 'G'
+↗️
    -diff 'G'
 'g'
 
     'G' - diff
@@ -147,7 +147,7 @@
 ⟨ "Hello" "World" ⟩
 

That converts the first character of each string to uppercase! case.Upper is the case conversion function defined before, so that part makes sense. The rest of the function, (¨), would be pronounced "Under the First of Each", which… pretty much makes sense too? The First Each function extracts the first element of each list in hw, the part that used to be "hw" but is now "HW".

-↗️
    ¨ hw
+↗️
    ¨ hw
 "HW"
 
     case.Upper "hw"
@@ -163,14 +163,14 @@
 
•Out hw   ⥊⍉ [hw, ", ""!"]  # Hello, World!
 

None of these functions have a subject to the left, so they're all evaluated as prefix functions. But first, we have the array notation []. This syntax forms an array from its major cells hw and ", ""!" (another strand, a list of two strings). Because the major cells are both lists, we have another rank 2 array.

-↗️
    [hw, ", ""!"]
+↗️
    [hw, ", ""!"]
 ┌─                 
 ╵ "Hello" "World"  
   ", "    "!"      
                   ┘
 

The reason for forming this array is to interleave the elements, or we might say to read down the columns rather than across the rows. This ordering is done with a Transpose to exchange the two axes, then a Deshape to flatten it out, giving a list.

-↗️
     [hw, ", ""!"]
+↗️
     [hw, ", ""!"]
 ┌─              
 ╵ "Hello" ", "  
   "World" "!"   
@@ -180,7 +180,7 @@
 ⟨ "Hello" ", " "World" "!" ⟩
 

Finally, Join combines this list of strings into a single string.

-↗️
    hw   ⥊⍉ [hw, ", ""!"]
+↗️
    hw   ⥊⍉ [hw, ", ""!"]
     hw
 "Hello, World!"
 
@@ -249,7 +249,7 @@ (¨ GV ˜ ·+`GS) r

The first line here applies Proc to each character and the one before it, using ' ' as the character "before" the first. Proc{»𝔽¨} 𝕩 is a fancy way to write (»𝕩) Proc¨ 𝕩, which we'll explain in a moment. First, here's what the Nudge function » does.

-↗️
    hw
+↗️
    hw
 "Hello, World!"
     »hw
 " Hello, World"
@@ -257,7 +257,7 @@
 

It moves its argument forward by one, adding a space character (the array's fill) but keeping the same length. This gives the previous characters that we want to use for Proc's left argument. Here Each is used with two arguments, so that it iterates over them simultaneously, like a "zip" in some languages.

What about the fancy syntax Proc{»𝔽¨} 𝕩? The block {»𝔽¨} is an immediate 1-modifier because it uses 𝔽 for an operand but not the arguments 𝕨 or 𝕩. This means it acts on Proc only, giving »Proc¨, which is a train because it ends in a function . Following the rules for a 3-train, (»Proc¨)𝕩 expands to (»𝕩) Proc¨ (𝕩), and since is the identity function, 𝕩 is 𝕩.

Since a display of lots of namespaces isn't too enlightening, we'll skip ahead and show what the results of GV and GS on those lists would be. GV turns each character into a string, except it makes a space into the empty string. GS has a 1 in the places where we want to split the string.

-↗️
    sp  ' '=hw
+↗️
    sp  ' '=hw
     gv  (1-sp) ¨ hw
     gs  sp  »= hw
 
@@ -312,18 +312,18 @@
 
 
 

There are actually three train groupings here: from right to left, ·+`GS, GV ˜ , and ¨ . Two of them are 2-trains, which apply one function to the result of another, but the one with is a 3-train, applying a function to two results. In the end, functions GS and GV are applied to r. In fact, to evaluate the entire train we can replace these two functions with their results, giving ¨ (GV r) ˜ ·+`(GS r).

-↗️
    ¨ gv ˜ ·+`gs
+↗️
    ¨ gv ˜ ·+`gs
 ⟨ "Hel" "lo," "World!" ⟩
 

In this expression, Nothing can be removed without changing the meaning. It's used in the train to force +` to apply to GS as a 2-train instead of also taking ˜ as a left argument. The Scan +` is a prefix sum, progressively adding up the numbers in gs.

-↗️
    gs
+↗️
    gs
 ⟨ 0 0 0 1 0 0 1 0 0 0 0 0 0 ⟩
 
     +`gs
 ⟨ 0 0 0 1 1 1 2 2 2 2 2 2 2 ⟩
 

The next bit uses Swap to switch the order: gv ˜ +`gs is (+`gs) gv, but sometimes the different order can read better (here it was mostly to squeeze Nothing into the program, I'll admit). Group then splits gv up based on the indices given: the first three elements become element 0 of the result, the next three element 1, and the rest element 2.

-↗️
    (+`gs)  gv
+↗️
    (+`gs)  gv
 ┌─                                                                
 · ⟨ "H" "e" "l" ⟩ ⟨ "l" "o" "," ⟩ ⟨ ⟨⟩ "W" "o" "r" "l" "d" "!" ⟩  
                                                                  ┘
diff --git a/docs/doc/range.html b/docs/doc/range.html
index 887f9833..52bbc54d 100644
--- a/docs/doc/range.html
+++ b/docs/doc/range.html
@@ -86,14 +86,14 @@
 ⟨ 0 1 2 0 0 0 6 0 ⟩
 

Now at any given position the index of the last 1, if there is any, is the maximum of all the adjusted indices so far. That's a scan `.

-↗️
    ` b × ↕≠b
+↗️
    ` b × ↕≠b
 ⟨ 0 1 2 2 2 2 6 6 ⟩
 
     (`  × ) b   # As a tacit function
 ⟨ 0 1 2 2 2 2 6 6 ⟩
 

Where there aren't any previous 1s, this returns an index of 0, which is the same as the result where there is a 1 at index 0. If it's important to distinguish these possibilities, the indices can be increased by one, so that the result is 0 if there are no 1s, and 1 for a 1 at the start. To bring it back into alignment with the argument, either this result can be decreased by 1 or an initial element can be added to the argument.

-↗️
    ` b × 1 + ↕≠b
+↗️
    ` b × 1 + ↕≠b
 ⟨ 0 2 3 3 3 3 7 7 ⟩
 

List range

diff --git a/docs/doc/rank.html b/docs/doc/rank.html index 631693cf..409fee4b 100644 --- a/docs/doc/rank.html +++ b/docs/doc/rank.html @@ -104,7 +104,7 @@

What's it mean for Nudge to shift the "entire table"? The block above shows that it shifts downward, but what's really happening is that Nudge treats 𝕩 as a collection of major cells—its rows—and shifts these. So it adds an entire row and moves the rest of the rows downwards. Nudge Cells appears similar, but it's acting independently on each row, and the values that it moves around are major cells of the row, that is, rank-0 units.

Here's an example showing how Cells can be used to shift each row independently, even though it's not possible to shift columns like this (in fact the best way to do that would be to transpose in order to work on rows). It uses the not-yet-introduced dyadic form of Cells, so you might want to come back to it after reading the next section.

-↗️
    ("∘∘") »˘ a
+↗️
    ("∘∘") »˘ a
 ┌─          
 ╵"abcdefgh  
   ∘ijklmno  
@@ -112,7 +112,7 @@
            ┘
 

You can also see how Cells splits its argument into rows using a less array-oriented primitive: Enclose just wraps each row up so that it appears as a separate element in the final result.

-↗️
    <˘ a
+↗️
    <˘ a
 ⟨ "abcdefgh" "ijklmnop" "qrstuvwx" ⟩
 

Enclose also comes in handy for the following task: join the rows in an array of lists, resulting in an array where each element is a joined row. The obvious guess would be "join cells", ˘, but it doesn't work, because each can return a result with a different length. Cells tries to make each result of into a cell, when the problem was to use it as an element. But a 0-cell is an enclosed element, so we can close the gap by applying < to a joined list: <.

@@ -131,7 +131,7 @@

This approach can apply to more complicated functions as well. And because the result of < always has the same shape, ⟨⟩, the function <𝔽˘ can never have a shape agreement error. So if 𝔽˘ fails, it can't hurt to check <𝔽˘ and see what results 𝔽 is returning.

Two arguments

When given two arguments, Cells tries to pair their cells together. Starting simple, a unit (whether array or atom) on either side will be paired with every cell of the other argument.

-↗️
    '∘' »˘ a
+↗️
    '∘' »˘ a
 ┌─          
 ╵"∘abcdefg  
   ∘ijklmno  
@@ -139,7 +139,7 @@
            ┘
 

If you want to use this one-to-many behavior with an array, it'll take more work: since you're really only mapping over one argument, bind the other inside Cells.

-↗️
    "∘∘" »˘ a
+↗️
    "∘∘" »˘ a
 Error: ˘: Leading axis of arguments not equal (⟨2⟩ ≡ ≢𝕨, 3‿8 ≡ ≢𝕩)
 
     "∘∘"»˘ a
@@ -150,7 +150,7 @@
            ┘
 

This is because the general case of Cells does one-to-one matching, pairing the first axis of one argument with the other. For this to work, the two arguments need to have the same length.

-↗️
     "012" »˘ a,  (3"UVWXYZ") »˘ a 
+↗️
     "012" »˘ a,  (3"UVWXYZ") »˘ a 
 ┌─                           
 · ┌─           ┌─            
   ╵"0abcdefg   ╵"UVabcdef    
@@ -160,7 +160,7 @@
                             ┘
 

The arguments might have different ranks: for example, "012" has rank 1 and a has rank 2 above. That's fine: it just means Cells will pass arguments of rank 0 and 1 to its operand. You can see these arguments using Pair Cells, ˘, so that each cell of the result is just a list of the two arguments used for that call.

-↗️
    "012" ˘ a
+↗️
    "012" ˘ a
 ┌─                  
 ╵ ┌·    "abcdefgh"  
   ·'0'              
@@ -196,7 +196,7 @@
 ⟨ "abc" "def" ⟩
 

The function 𝔽k, for k0, operates on the k-cells of its arguments—that is, it maps over all but the last k axes. For any given argument a, ranks k and k-=a are the same, as long as k0 and (k-=a)¯1. So rank 2 is rank ¯3 for a rank-5 array. The reason this option is useful is that the same rank might be applied to multiple arguments, either with multiple function calls or one call on two arguments. Let's revisit an example with Cells from before, shifting the same string into each row of a table. The function » should be called on rank-1 strings, but because the argument ranks are different, a negative rank can't get down to rank 1 on both sides. Positive rank 1 does the job, allowing us to unbundle the string "∘∘" so that »1 is a standalone function.

-↗️
    "∘∘"»˘ a
+↗️
    "∘∘"»˘ a
 ┌─          
 ╵"∘∘abcdef  
   ∘∘ijklmn  
@@ -260,7 +260,7 @@
 ⟨ 2 ¯1 3 ⟩
 

But a rank of 1 works the best because it also defines a matrix-matrix product. Which as shown below does the same transformation to the cells of the right-hand-side matrix, instead of the elements of a vector. This works because × and +˝ work on the leading axes of their arguments. When 1 is applied, these axes are the last axis of 𝕨 and the first axis of 𝕩. Which… is kind of weird, but it's what a matrix product is.

-↗️
    +˝ 010 × 123×110
+↗️
    +˝ 010 × 123×110
 ⟨ 2 20 ⟩
 
     m +˝×1 123×110
diff --git a/docs/doc/rebqn.html b/docs/doc/rebqn.html
index a3d0c97e..36c0439c 100644
--- a/docs/doc/rebqn.html
+++ b/docs/doc/rebqn.html
@@ -27,7 +27,7 @@
 ⟨ 0 1 2 3 4 5 6 7 8 ⟩
 

Options can be used in any combination. Here's a calculator REPL:

-↗️
    calcRepl  •ReBQN {repl"strict", primitivescalcFns}
+↗️
    calcRepl  •ReBQN {repl"strict", primitivescalcFns}
 
     CalcRepl "b ← 1 - a←6"
 ¯5
@@ -37,19 +37,19 @@
 

REPL mode

The repl property can have the values "none", "strict", and "loose". If no value is given it's equivalent to "none", which means that the resulting function has no memory and each evaluation is independent from the others. But the values "strict" and "loose" make evaluations take place in a shared scope. Now a variable defined at the top level of one source string is visible when later ones are evaluated, and can be viewed and modified.

-↗️
    do  •ReBQN {repl"loose"}
+↗️
    do  •ReBQN {repl"loose"}
 
     Do¨ "a←4""⟨a,b←5⟩""{⟨a↩𝕩,b⟩}8"
 ⟨ 4 ⟨ 4 5 ⟩ ⟨ 8 5 ⟩ ⟩
 

A different •ReBQN result has its own scope and can't access these variables.

-↗️
    doNot  •ReBQN {repl"loose"}
+↗️
    doNot  •ReBQN {repl"loose"}
 
     DoNot "b" # surprised when this fails
 Error: Undefined identifier
 

The difference in "strict" and "loose" is that a loose REPL can define a variable again, which just changes its value (under the covers, the is treated as a ).

-↗️
    Do "a ← ¯1"
+↗️
    Do "a ← ¯1"
 ¯1
     Do "a ← b‿a"
 ⟨ 5 ¯1 ⟩
diff --git a/docs/doc/replicate.html b/docs/doc/replicate.html
index 1e1fabc5..6ffec63c 100644
--- a/docs/doc/replicate.html
+++ b/docs/doc/replicate.html
@@ -149,7 +149,7 @@
         ┘
 

Here the 20 indicates that the first row of b is copied twice and the second is ignored, while 10011 picks out three entries from that row. As in the single-axis case, 𝕩 can have extra trailing axes that aren't modified by 𝕨. The rules are that 𝕨 can't have more elements than axes of 𝕩 (so (𝕨)≤=𝕩), and that each element has to have the same length as the corresponding axis—or it can be a unit, as shown below.

-↗️
    <2,<3 / b
+↗️
    <2,<3 / b
 ┌─                               
 ╵ 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4  
   0 0 0 1 1 1 2 2 2 3 3 3 4 4 4  
@@ -158,7 +158,7 @@
                                 ┘
 

Above, both elements of 𝕨 are enclosed numbers. An individual element doesn't have to be enclosed, but I don't recommend this, since if none of them are enclosed, then 𝕨 will have depth 1 and it will be interpreted as replicating along the first axis only.

-↗️
    2,3 / b
+↗️
    2,3 / b
 ┌─           
 ╵ 0 1 2 3 4  
   0 1 2 3 4  
@@ -169,7 +169,7 @@
 

The example above has a different result from the previous one! The function <¨/ could be used in place of / to replicate each axis by a different number.

If 𝕨 is ⟨⟩, then it has depth 1, but is handled with the multidimensional case anyway, giving a result of 𝕩. The one-dimensional case could also only ever return 𝕩, but it would be required to have length 0, so this convention still only extends the simple case.

-↗️
    b  ⟨⟩ / b
+↗️
    b  ⟨⟩ / b
 1
 

Indices

@@ -243,7 +243,7 @@ Error: /: Argument must have rank 1 (3‿6 ≡ ≢𝕩)

Error. But the two 1s are located at 03 and 12. What's wrong with those? First, let's note that you can find these indices if you need to, using Replicate. Make the list of all indices ↕≢𝕩, and filter Over Deshape ().

-↗️
    /(↕≢) r
+↗️
    /(↕≢) r
 ⟨ ⟨ 0 3 ⟩ ⟨ 1 2 ⟩ ⟩
 

The issue with this function is that it's not consistent with the result of / on a list. This is because the extension gives element indices, which are lists, while the original / gives single-number indices, which is only possible when 𝕩 has rank 1.

diff --git a/docs/doc/reshape.html b/docs/doc/reshape.html index 68537bf0..e6039f3b 100644 --- a/docs/doc/reshape.html +++ b/docs/doc/reshape.html @@ -75,7 +75,7 @@ ⟨ 135 136 137 145 146 147 235 236 237 245 246 247 ⟩

The elements are ordered in reading order—left to right, then top to bottom. This means that leading axes "matter more" for ordering: if one element comes earlier in the first axis but later in the second than some other element, it will come first in the result. In another view, elements are ordered according to their indices, leading to the name index order for this ordering. To be precise, deshaping the array of indices for an array always gives a sorted array.

-↗️
    ↕≢a
+↗️
    ↕≢a
 ┌─                               
 ╎ ⟨ 0 0 0 ⟩ ⟨ 0 0 1 ⟩ ⟨ 0 0 2 ⟩  
   ⟨ 0 1 0 ⟩ ⟨ 0 1 1 ⟩ ⟨ 0 1 2 ⟩  
@@ -99,7 +99,7 @@
 

The left argument of Reshape gives the shape of the result, except that one entry can be left unspecified for BQN to fill in. We'll look at the cases where a full shape is given first.

Matching lengths

If the number of elements implied by the given shape—that is, ×´𝕨—is equal to the number of elements in 𝕩, then 𝕩 is simply rearranged to match that shape. The element list is kept the same, so that the deshaped result matches the deshaped right argument.

-↗️
    a
+↗️
    a
 ┌─             
 ╎ 135 136 137  
   145 146 147  
@@ -135,7 +135,7 @@
 

Non-matching lengths

If 𝕨 implies a smaller number of elements than are present initially, then only the initial elements of 𝕩 are used. Here the result stops at 237, three-quarters of the way through a, because at that point the result is filled up.

-↗️
    33  a
+↗️
    33  a
 ┌─             
 ╵ 135 136 137  
   145 146 147  
@@ -143,7 +143,7 @@
               ┘
 

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

-↗️
    15  a
+↗️
    15  a
 ⟨ 135 136 137 145 146 147 235 236 237 245 246 247 135 136 137 ⟩
 
     4  0
diff --git a/docs/doc/reverse.html b/docs/doc/reverse.html
index cd984689..4d594095 100644
--- a/docs/doc/reverse.html
+++ b/docs/doc/reverse.html
@@ -94,7 +94,7 @@
 Error: 𝕨⌽𝕩: Length of compound 𝕨 must be at most rank of 𝕩
 

The expression below rotates the first (vertical) axis of tab by one element, and second by two. So the line of capital letters goes from being one away from the top, up to the top, and the column with '2' goes from horizontal index 2 to index 0.

-↗️
    12  tab
+↗️
    12  tab
 ┌─      
 ╵"CDAB  
   2301  
@@ -102,7 +102,7 @@
        ┘
 

The vertical and horizontal rotations are independent, and could also be done with two s and a ˘. The multi-axis form is more convenient, and can potentially be evaluated faster than multiple separate rotations in the cases where it shows up.

-↗️
    1  2 ˘ tab
+↗️
    1  2 ˘ tab
 ┌─      
 ╵"CDAB  
   2301  
diff --git a/docs/doc/scan.html b/docs/doc/scan.html
index bac2f4c5..9856380b 100644
--- a/docs/doc/scan.html
+++ b/docs/doc/scan.html
@@ -143,7 +143,7 @@
                 ┘
 

If 𝕨 is given, it must have the same shape as a major cell of 𝕩 (this is why 𝕨 needs to be enclosed when 𝕩 is a list: in general it's an array). Then the first result cell is found by applying 𝔽 to elements of 𝕨 and 𝕩, and the computation continues as in the one-argument case for remaining cells.

-↗️
    3210 +` a
+↗️
    3210 +` a
 ┌─              
 ╵ 1 2.25 'b' ∞  
   0 2.25 'c' ∞  
diff --git a/docs/doc/search.html b/docs/doc/search.html
index a92b25c1..948891e1 100644
--- a/docs/doc/search.html
+++ b/docs/doc/search.html
@@ -200,21 +200,21 @@
 ⟨ 0 2 ⟩
 

The first thing you might try to search for just one element does not go so well (and yes, this is a bad thing).

-↗️
    stuff  "string"
+↗️
    stuff  "string"
 ⟨ 4 4 4 4 4 4 ⟩
 

Instead of interpreting 𝕩 as a single element, Index of treats it as a list, and 𝕨 doesn't even contain characters! Well, Enclose (<) makes an array from a single element…

-↗️
    stuff ⊐< "string"
+↗️
    stuff ⊐< "string"
 ┌·   
 · 2  
     ┘
 

This result has the right information, but is enclosed and could break the program later on. Remember that the result of a search function is always an array. We really want the first element.

-↗️
    stuff < "string"
+↗️
    stuff < "string"
 2
 

If 𝕨 is fixed, then the version I prefer is to use Under to enclose the argument and then un-enclose the result. It requires 𝕨 to be bound to because otherwise Under would enclose 𝕨 as well, since it applies 𝔾 to both arguments.

-↗️
    stuff< "string"
+↗️
    stuff< "string"
 2
 

For Member of, the equivalent is stuff<.

diff --git a/docs/doc/select.html b/docs/doc/select.html index 566f6484..978da307 100644 --- a/docs/doc/select.html +++ b/docs/doc/select.html @@ -117,7 +117,7 @@

More generally, 𝕨 can be an array of any rank. Each of its 0-cells—containing a single number—is replaced with a cell of 𝕩 in the result. The result's shape is then made up of the shape of 𝕨 and the major cell shape of 𝕩: it's (𝕨)1↓≢𝕩.

When 𝕩 is a list, the result has the same shape as 𝕨. Elements of 𝕨 are replaced one-for-one with elements of 𝕩.

-↗️
    2|m
+↗️
    2|m
 ┌─               
 ╵ 0 1 1 0 1 1 0  
   0 1 0 0 1 0 1  
diff --git a/docs/doc/selfcmp.html b/docs/doc/selfcmp.html
index 05490758..d4cb1cbc 100644
--- a/docs/doc/selfcmp.html
+++ b/docs/doc/selfcmp.html
@@ -202,7 +202,7 @@
 ⟨ 0 1 2 ⟩
 

Applying both separately is a different story, and gives completely interesting results. These results contain all information from the original argument, as indicates which cells it contained and indicates where they were located. The function Select () reconstructs the argument from the two values.

-↗️
     c
+↗️
     c
 ┌─        
 ╵"yellow  
   orange  
diff --git a/docs/doc/shape.html b/docs/doc/shape.html
index 50140270..eef019ab 100644
--- a/docs/doc/shape.html
+++ b/docs/doc/shape.html
@@ -31,7 +31,7 @@
 4
 

The length is the first element of the shape, and the rank is the length of the shape—the number of axes. For another example, taking the first (and only) cell of arr gives an array with shape 326, length 3, and rank 3, as we can see by applying each function to arr.

-↗️
    = {𝕎𝕩}¨< arr
+↗️
    = {𝕎𝕩}¨< arr
 ⟨ ⟨ 3 2 6 ⟩ 3 3 ⟩
 

Applying Shape and the other two functions to an atom shows a shape of ⟨⟩ (the empty list), and a rank of zero and length of 1. The same is true of an enclosed array, which like an atom is a kind of unit.

diff --git a/docs/doc/shift.html b/docs/doc/shift.html index 84684f8a..a1e8aa25 100644 --- a/docs/doc/shift.html +++ b/docs/doc/shift.html @@ -36,7 +36,7 @@ ⟨ 1 2 2 4 3 5 6 ⟩

In this way » refers to a sequence containing the previous element at each position. By default the array's fill is used for the element before the first, and a right argument can be given to provide a different one.

-↗️
     » s
+↗️
     » s
 ⟨ ∞ 1 2 2 4 3 5 ⟩
 
     » s
@@ -44,7 +44,7 @@
 

It may appear backwards that », which typically means "go to the next item", is used to represent the previous item. In fact there is no conflict: the symbol » describes what position each cell of 𝕩 will have in the result, but in this context we are interested in knowing what argument value occurs in a particular result position. By moving all numbers into the future we ensure that a number in the present comes from the past. To keep your intuition functioning in these situations, it may help to think of the arrow point as fixed at some position in the result while the tail stretches back to land on the argument position where it comes from.

Switching the direction of the arrow, we get an operation that pulls the next value into each position:

-↗️
    s  «s
+↗️
    s  «s
 ┌─               
 ╵ 1 2 2 4 3 5 6  
   2 2 4 3 5 6 0  
@@ -53,7 +53,7 @@
 ⟨ 1 0 2 ¯1 2 1 ¯6 ⟩
 

The differences here are the same as -» s, except that they are shifted over by one, and it is the last value in the sequence that is compared with a fill value, not the first. These techniques adapt easily to more complicated operations. A symmetric difference is found by subtracting the previous element from the next, and dividing by two:

-↗️
    2÷˜ (»-«) s
+↗️
    2÷˜ (»-«) s
 ⟨ ¯1 ¯0.5 ¯1 ¯0.5 ¯0.5 ¯1.5 2.5 ⟩
 
     2÷˜ (˝» - ˝«) s  # Repeat at the ends instead of using fills
@@ -72,7 +72,7 @@
 ⟨ 1 1 0 1 1 0 0 0 ⟩
 

With a number in big-endian format, a right shift might be logical, shifting in zeros, or arithmetic, shifting in copies of the highest-order bit (for little-endian numbers, this applies to left shifts rather than right ones). The two kinds of shift can be performed with similar code, using 0 or 𝕩 for the inserted cell.

-↗️
    3 0» i    # Logical right shift
+↗️
    3 0» i    # Logical right shift
 ⟨ 0 0 0 1 0 0 1 1 ⟩
 
     3 (⊏»⊢) i  # Arithmetic right shift
diff --git a/docs/doc/take.html b/docs/doc/take.html
index 1c976976..e141a489 100644
--- a/docs/doc/take.html
+++ b/docs/doc/take.html
@@ -125,7 +125,7 @@
 

Now Take and Drop taken together don't include the whole array. Take includes the elements that are selected on every axis, while Drop excludes the ones selected on any axis. They are opposite corners that meet at some point in the middle of the array (here, at the spot between 2 and 11).

Any integer values at all can be used, in any combination. Here one axis is shortened and the other's padded with fills. The result of Take has shape |𝕨, maybe plus some trailing axes from 𝕩. Of course, if that's too big for your available memory, your BQN implementation probably can't compute it for you!

-↗️
    3¯12  m
+↗️
    3¯12  m
 ┌─                                
 ╵ 0 0 0 0 0  0  1  2  3  4  5  6  
   0 0 0 0 0 10 11 12 13 14 15 16  
diff --git a/docs/doc/train.html b/docs/doc/train.html
index 61e253ea..1f7c1f5b 100644
--- a/docs/doc/train.html
+++ b/docs/doc/train.html
@@ -52,20 +52,20 @@
 ⟨ 0 1 2 3 0 0 4 1 3 5 6 ⟩
 

Each 't' is 0, each 'a' is 1, and so on. We'd like to discard some of the information from Classify, to just find whether each major cell had a new value. Here are the input and desired result:

-↗️
    sc   "tacittrains"
+↗️
    sc   "tacittrains"
 ┌─                       
 ╵ 0 1 2 3 0 0 4 1 3 5 6  
   1 1 1 1 0 0 1 0 0 1 1  
                         ┘
 

The result should be 1 when a new number appears, higher than all the previous numbers. To do this, we first find the highest previous number by taking the maximum-scan ` of the argument, then shifting to move the previous maximum to the current position. The first cell is always new, so we shift in a ¯1, so it will be less than any element of the argument.

-↗️
    ¯1 » `sc
+↗️
    ¯1 » `sc
 ⟨ ¯1 0 1 2 3 3 3 4 4 4 5 ⟩
     (¯1»⌈`) sc
 ⟨ ¯1 0 1 2 3 3 3 4 4 4 5 ⟩
 

Now we compare the original list with the list of previous-maximums.

-↗️
    sc > ¯1»⌈`sc
+↗️
    sc > ¯1»⌈`sc
 ⟨ 1 1 1 1 0 0 1 0 0 1 1 ⟩
     (⊢>¯1»⌈`) sc
 ⟨ 1 1 1 1 0 0 1 0 0 1 1 ⟩
diff --git a/docs/doc/transpose.html b/docs/doc/transpose.html
index 8c9841b3..998840b8 100644
--- a/docs/doc/transpose.html
+++ b/docs/doc/transpose.html
@@ -21,7 +21,7 @@
       ┘
 

Transpose is named this way because it exchanges the two axes of the matrix. Above you can see that while mat has shape 23, mat has shape 32, and we can also check that the element at index ij in mat is the same as the one at ji in mat:

-↗️
    10  mat
+↗️
    10  mat
 3
     01   mat
 3
@@ -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    
@@ -64,7 +64,7 @@
                            ┘
 

To exchange multiple axes, use the Repeat modifier. A negative power moves axes in the other direction, just like how Rotate handles negative left arguments. In particular, to move the last axis to the front, use Undo (as you might expect, this exactly inverts ).

-↗️
     3 a23456
+↗️
     3 a23456
 ⟨ 5 6 2 3 4 ⟩
 
       a23456
@@ -72,11 +72,11 @@
 

In fact, we have ≢⍉k a ←→ k⌽≢a for any whole number k and array a.

To move axes other than the first, use the Rank modifier in order to leave initial axes untouched. A rank of k>0 transposes only the last k axes while a rank of k<0 ignores the first |k axes.

-↗️
     3 a23456
+↗️
     3 a23456
 ⟨ 2 3 5 6 4 ⟩
 

And of course, Rank and Repeat can be combined to do more complicated transpositions: move a set of contiguous axes with any starting point and length to the end.

-↗️
     ¯1 a23456
+↗️
     ¯1 a23456
 ⟨ 2 6 3 4 5 ⟩
 

Using these forms (and the Rank function), we can state BQN's generalized matrix product swapping rule:

@@ -84,28 +84,28 @@

Certainly not as concise as APL's version, but not a horror either. BQN's rule is actually more parsimonious in that it only performs the axis exchanges necessary for the computation: it moves the two axes that will be paired with the matrix product into place before the product, and directly exchanges all axes afterwards. Each of these steps is equivalent in terms of data movement to a matrix transpose, the simplest nontrivial transpose to perform. Also remember that for two-dimensional matrices both kinds of transposition are the same, so that APL's simpler rule MP MP˜ holds in BQN on rank 2.

Axis permutations of the types we've shown generate the complete permutation group on any number of axes, so you could produce any transposition you want with the right sequence of monadic transpositions with Rank. However, this can be unintuitive and tedious. What if you want to transpose the first three axes, leaving the rest alone? With monadic Transpose you have to send some axes to the end, then bring them back to the beginning. For example [following four or five failed tries]:

-↗️
     ¯2  a23456  # Restrict Transpose to the first three axes
+↗️
     ¯2  a23456  # Restrict Transpose to the first three axes
 ⟨ 3 4 2 5 6 ⟩
 

In a case like this the dyadic version of , called Reorder Axes, is much easier.

Reorder Axes

Transpose also allows a left argument that specifies a permutation of 𝕩's axes. For each index pi𝕨 in the left argument, axis i of 𝕩 is used for axis p of the result. Multiple argument axes can be sent to the same result axis, in which case that axis goes along a diagonal of 𝕩, and the result will have a lower rank than 𝕩 (see the next section).

-↗️
     13204  a23456
+↗️
     13204  a23456
 ⟨ 5 2 4 3 6 ⟩
 
      12200  a23456  # Don't worry too much about this case though
 ⟨ 5 2 3 ⟩
 

Since this kind of rearrangement can be counterintuitive, it's often easier to use when specifying all axes. If p≠≢a, then we have pa ←→ p⊏≢a.

-↗️
     13204  a23456
+↗️
     13204  a23456
 ⟨ 3 5 4 2 6 ⟩
 

BQN makes one further extension, which is to allow only some axes to be specified (this is the only difference in dyadic relative to APL). Then 𝕨 will be matched up with leading axes of 𝕩. Those axes are moved according to 𝕨, and remaining axes are placed in order into the gaps between them.

-↗️
     024  a23456
+↗️
     024  a23456
 ⟨ 2 5 3 6 4 ⟩
 

In particular, the case with only one axis specified is interesting. Here, the first axis ends up at the given location. This gives us a much better solution to the problem at the end of the last section.

-↗️
     2  a23456  # Restrict Transpose to the first three axes
+↗️
     2  a23456  # Restrict Transpose to the first three axes
 ⟨ 3 4 2 5 6 ⟩
 

Finally, it's worth noting that, as monadic Transpose moves the first axis to the end, it's equivalent to Reorder Axes with a "default" left argument: (=-1˙).

diff --git a/docs/doc/under.html b/docs/doc/under.html index 2a06e458..4ec761a8 100644 --- a/docs/doc/under.html +++ b/docs/doc/under.html @@ -58,7 +58,7 @@ ┘

When used with Under, the function 1 applies to the first column, rotating it. The result of 𝔽 needs to be compatible with the selection function, so Rotate works but trying to drop an element is no good:

-↗️
    1(˘) a
+↗️
    1(˘) a
 Error: ⁼: Inverse not found
 

BQN can detect lots of structural functions when written tacitly; see the list of recognized forms in the spec. You can also include computations on the shape. For example, here's a function to reverse the first half of a list.

diff --git a/docs/help/change.html b/docs/help/change.html index 172b4c58..f8b6c103 100644 --- a/docs/help/change.html +++ b/docs/help/change.html @@ -21,12 +21,12 @@

n F: Modify

→full documentation

Apply function F to existing variable n, and assign the result back to n.

-↗️
     b 
+↗️
     b 
 ".dlrow eht ni ees ot hsiw uoy egnahc eht eB"
 

n F v: Modify

→full documentation

Assign n F v to n.

-↗️
     b ˜ 6
+↗️
     b ˜ 6
 " eht ni ees ot hsiw uoy egnahc eht eB"
 
diff --git a/docs/tutorial/variable.html b/docs/tutorial/variable.html index 1bb916ac..5e05d336 100644 --- a/docs/tutorial/variable.html +++ b/docs/tutorial/variable.html @@ -24,11 +24,11 @@ ⟨ 3 7 ⟩

A variable can't be defined twice in the same scope. Later we'll work with functions and other pieces of code that create their own scopes, but for now all you need to know is that all the code in a tutorial runs in the same scope. So three is already defined, and can't be defined again.

-↗️
    three  4
+↗️
    three  4
 Error: Redefinition
 

It's a little crazy to call them variables if the definition can never change, right? Doesn't "variable" mean "able to change"? Fortunately, this is one way in which BQN isn't crazy. You can modify a variable's value with the arrow provided it's already been defined. This never does anything to the original value: that value stays the same; it's just (probably) not the value of the modified variable any more.

-↗️
    three  4
+↗️
    three  4
 
     three = 3   # Wait why did I do that
 0
@@ -46,7 +46,7 @@
 

Does BQN not know about capital letters? Does it object to self-reference? Why is "BQN" green? At least there's an error message, and a "role" is something we've heard about before. Assignment means anything written with a leftward arrow—either definition or modification.

I'll first confuse you a little more by pointing out that BQN's variables are case-insensitive, and even underscore-insensitive!

-↗️
    three
+↗️
    three
 3
     thrEe
 3
@@ -60,7 +60,7 @@
 3
 

But the syntax highlighter still seems to care, and you'll get a strange result if you try to apply a function to one of the uppercase spellings:

-↗️
    - Three
+↗️
    - Three
 -3{𝔽}
 
     - _three
@@ -118,7 +118,7 @@
 

This strategy allows us to break down a program into smaller parts. However, you can only name a function in this way, not an expression. We'll explain later how to turn an expression into an explicit function. But one thing remains true regardless of how a function is created: functions are just another kind of BQN value, and giving a function a name uses the ordinary definition arrow , not any special syntax.

Even if you define a variable to be a function at first, you're not locked in to that choice. You can modify the variable to have a different value (but remember to change the casing to match the new value's role!). If it's a data value, you'll still be able to call it as a function: it will return itself.

-↗️
    Base2
+↗️
    Base2
 +⟜(2⊸×)´∘⌽
 
     base2  16   # Change it to a number
@@ -312,7 +312,7 @@
 ⟨ 4 5 6 ⟩
 

But this changes the value of a to a completely unrelated value. What if I want to apply a transformation to a, for example to subtract one? Of course I can write the value a on the right hand side of the assignment, but that's extra work and doesn't really seem to represent what I'm doing, which is conceptually just to apply a function to a. So BQN also has a shorthand, called modified assignment. Here, the modified assignment - subtracts a value from a.

-↗️
    a  a - 1
+↗️
    a  a - 1
     a
 ⟨ 3 4 5 ⟩
 
@@ -320,31 +320,31 @@
 ⟨ 2 3 4 ⟩
 

(In case you're wondering why I didn't have to write a again that last time, the evaluator suppresses the printed result for ordinary assignments but not modified ones. This is a feature of my website software and not the BQN language). It looks a lot like the special assignment operators +=, /=, and so on that you'll see in C or Javascript. What BQN brings to the table is that you can use any two-argument function at all here, because two-argument function are always written as operators. For example, we can prepend some elements to a:

-↗️
    a ˜ 01
+↗️
    a ˜ 01
 ⟨ 0 1 2 3 4 ⟩
 

But what about functions with only one argument? It's possible to do this using a dummy right argument such as the null character, @. To turn a function that takes one argument into one that takes two, we can compose it with a function that takes two arguments and returns one of them. The left one, since the variable to modify is on the left hand side. Perhaps… Left? ()?

-↗️
    "abcd"  "wxyz"
+↗️
    "abcd"  "wxyz"
 "dcba"
 
     a  @
 ⟨ 4 3 2 1 0 ⟩
 

But fortunately, there's a simpler syntax as well: write your one-argument function before with no right hand side. Bit of a Yoda vibe: "a reversed is".

-↗️
    a 
+↗️
    a 
 ⟨ 0 1 2 3 4 ⟩
 
     a 4-           # And back again
 ⟨ 4 3 2 1 0 ⟩
 

Notice that there's no need for parentheses: modifiers bind more strongly than the assignment character. Now what if we want to decrease the last two elements of a? That is, we want to compute the following array while storing it in a.

-↗️
    -4(¯2) a
+↗️
    -4(¯2) a
 ⟨ 4 3 2 ¯3 ¯4 ⟩
 
     a                # It hasn't changed, of course
 ⟨ 4 3 2 1 0 ⟩
 

The code to do this looks the same as what we did with Reverse (). Again we don't have to parenthesize the function, because modifiers associate from left to right, so Under () binds to its operands before Compose () does.

-↗️
    a -4(¯2)
+↗️
    a -4(¯2)
 ⟨ 4 3 2 ¯3 ¯4 ⟩
 
diff --git a/md.bqn b/md.bqn index 4e1cb798..63a63d6d 100644 --- a/md.bqn +++ b/md.bqn @@ -200,6 +200,19 @@ Markdown ← {filename𝕊𝕩: ⟨¬ useEntity , entities ⊏˜ useEntity/ind , /useEntity⟩ } + # Function to build REPL link + # May include previous statements to define variables + makeLink ← { + lines ← names ← nline ← ⟨⟩ + { used‿assigned‿aline 𝕊 ls: + prev ← lines ⊏˜ ⍷∧ (names ∊ used) / nline + names ∾↩ assigned + nline ∾↩ (≠lines) + aline + lines ∾↩ ls + JoinLines prev ∾ 𝕩 + } + } + # Non-empty lines in code blocks have 4 leading spaces ProcCode ← { # Strip the leading spaces @@ -235,7 +248,21 @@ Markdown ← {filename𝕊𝕩: r ← show ('#'≠⊑∘⊢)◶⟨"",E⎊(ShowErr∘•CurrentError⊢)⟩⍟(0<≠∘⊢)¨ parts # Link that runs the code - lu ← tryURL ∾ Base64 ¯1 ↓ JoinLines parts + # Parse assignments and variables to add previous lines if needed + In ← 1=+⟜(↕2)⊸⍋ + Names ← (((-´"aA")×"AZ"⊸In)⊸+code) ⊔˜ 1-˜('_'≠code)⊸× + ma‿sp‿st ← {m∧code=𝕩}¨"↩ ‿" ⋄ id←sp