aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2022-07-05 16:46:42 -0400
committerMarshall Lochbaum <mwlochbaum@gmail.com>2022-07-05 16:46:42 -0400
commita25cb2b0bf26033c9bc778d816618a752d015d99 (patch)
tree7056712bb10bf509764e04e56267f106e50dbea0 /doc
parentdf5ddc0ed2fe48411645228c6e2d596be239a0c6 (diff)
Somehow, all the docs have now been edited
Diffstat (limited to 'doc')
-rw-r--r--doc/fromDyalog.md33
-rw-r--r--doc/fromJ.md14
-rw-r--r--doc/functional.md12
-rw-r--r--doc/glossary.md56
-rw-r--r--doc/group.md62
-rw-r--r--doc/map.md24
6 files changed, 105 insertions, 96 deletions
diff --git a/doc/fromDyalog.md b/doc/fromDyalog.md
index 6bdb99e6..c50d6028 100644
--- a/doc/fromDyalog.md
+++ b/doc/fromDyalog.md
@@ -17,8 +17,7 @@ BQN uses the [based array model](based.md), so that a Dyalog simple scalar corre
| Vector | List |
| Matrix | Table |
-BQN shares the terms "cell" and "major cell" with Dyalog, and uses
-"element" (which may mean different things to different Dyalog users) *not* for a 0-cell but for the value it contains.
+BQN shares the terms "[cell](array.md#cells)" and "major cell" with Dyalog, and uses "element" (which may mean different things to different Dyalog users) *not* for a 0-cell but for the value it contains.
### Roles
@@ -36,7 +35,7 @@ Dyalog uses value types (array, function, and so on) to determine syntax while B
BQN comments are written with `#`, not `â`. BQN strings use double quotes `""` while single quotes `''` enclose a character.
-BQN's functions use `{}`, like Dyalog's dfns. The names for inputs and self-reference are different:
+BQN's [block](block.md) functions use `{}`, like Dyalog's dfns. The names for inputs and self-reference are different:
| Dyalog | BQN |
|--------|-----|
@@ -47,15 +46,15 @@ BQN's functions use `{}`, like Dyalog's dfns. The names for inputs and self-refe
| `âµâµ` | `ð”¾` |
| `∇∇` | `ð•£` |
-BQN doesn't have guards: it uses modifiers or [control structures](control.md) instead. However, BQN function and modifier blocks have headers that allow pattern matching. See the [block](block.md) documentation.
+Blocks don't have guards exactly, but headers and predicates support some similar functionality (first-class functions can also be used for [control structures](control.md)). Headers can also be used to make a block more explicit about its inputs, more like a tradfn.
The assignment arrow `â†` defines a new variable in a block, while `↩` modifies an existing one.
-BQN uses the ligature character `‿` for stranding, instead of plain juxtaposition. It also has a [list notation](arrayrepr.md#brackets) using `⟨⟩`.
+BQN uses the ligature character `‿` for stranding, instead of plain juxtaposition. It also has a [list notation](arrayrepr.md#brackets) using `⟨⟩`, and `[]` for higher-rank arrays.
## For reading
-Here are some closest equivalents in Dyalog APL for the BQN functions that don't use the same glyphs as APL. Correspondence can be approximate, and `⌽` is just used as a decorator to mean "reverse some things".
+Here are some closest equivalents in Dyalog APL for the BQN functions that don't use the same glyphs. Correspondence can be approximate, and `⌽` is just used as a decorator to mean "reverse some things".
| BQN | `⋆` | `√` | `∧` | `∨` | `¬` | `=` | `≠` | `<` | `>` | `≢` | `⥊` |
|:-----:|:---:|:--------:|:-----:|:-----:|:-----:|:-----:|:---:|:---:|:---:|:---:|:---:|
@@ -74,11 +73,15 @@ Here are some closest equivalents in Dyalog APL for the BQN functions that don't
Modifiers are a little harder. Many have equivalents in some cases, but Dyalog sometimes chooses different functionality based on whether the operand is an array. In BQN an array is always treated as a constant function.
-| BQN | `¨` | `⌜` | `Ë` | `⎉` | `âŸ` | `Ëœ` | `∘` | `â—‹` | `⟜` |
-|:------:|:---:|:----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
-| Dyalog | `¨` | `∘.` | `⌿` | `â¤` | `â£` | `â¨` | `â¤` | `â¥` | `∘` |
+| BQN | `¨` | `⌜` | `Ë` | `⎉` | `âŸ` | `Ëœ` | `∘` | `â—‹` | `⟜` |
+|:------:|:---:|:----:|:---:|:----:|:---:|:---:|:----:|:---:|:---:|
+| Dyalog | `¨` | `∘.` | `⌿` | `â¤A` | `â£` | `â¨` | `â¤f` | `â¥` | `∘` |
-In BQN `⎉` is Rank and `∘` is Atop. Dyalog's Atop (`â¤`) and Over (`â¥`) were added in version 18.0.
+Some other BQN modifiers have been proposed as future Dyalog extensions:
+
+| BQN | `⌾` | `⚇` | `⊸` |
+|:---------------:|:---:|:---:|:---:|
+| Dyalog proposed | `â¢` [Under](https://aplwiki.com/wiki/Under) | `â¥` Depth | `â›` [Reverse Compose](https://aplwiki.com/wiki/Reverse_Compose)
## For writing
@@ -91,7 +94,7 @@ The form `Fâ£G` (Power with a function right operand; Power limit) must be impl
<tr><th> Glyph </th><th> Monadic </th><th> Dyadic </th> </tr>
<tr><td> <code>*</code> </td><td colspan=2><code>⋆</code></td> </tr>
<tr><td> <code>âŸ</code> </td><td colspan=2><code>⋆â¼</code></td> </tr>
-<tr><td> <code>!</code> </td><td><code>×´1+↕</code> </td><td> <code>-˜(+÷○(×´)⊢)1+↕∘⊣</code></td></tr>
+<tr><td> <code>!</code> </td><td><code>×´1+↕</code> </td><td> <code>(-÷○(×´)1⊸+)⟜↕˜</code></td></tr>
<tr><td> <code>○</code> </td><td> <code>π⊸×</code> </td><td> <code>•math</code></td> </tr>
<tr><td> <code>~</code> </td><td> <code>¬</code> </td><td> <code>¬∘∊/⊣</code></td> </tr>
<tr><td> <code>?</code> </td><td> <code>•rand.Range⚇0</code> </td><td> <code>•rand.Deal</code></td></tr>
@@ -102,10 +105,10 @@ The form `Fâ£G` (Power with a function right operand; Power limit) must be impl
<tr><td> <code>âª</code> </td><td> <code>⥊˘</code> </td><td> <code>∾</code></td> </tr>
<tr><td> <code>⌽</code> </td><td colspan=2><code>⌽⎉0‿1</code></td> </tr>
<tr><td> <code>↑</code> </td><td> <code>></code> </td><td> <code>↑</code></td> </tr>
-<tr><td> <code>↓</code> </td><td> <code><˘</code> </td><td> <code>↑</code></td> </tr>
+<tr><td> <code>↓</code> </td><td> <code><˘</code> </td><td> <code>↓</code></td> </tr>
<tr><td> <code>⊂</code> </td><td> <code><</code> </td><td> <code>+`⊸⊔</code></td> </tr>
<tr><td> <code>⊆</code> </td><td> <code><âŸ(0<≡)</code> </td><td> <code>(¬-˜⊢×·+`»⊸>)⊸⊔</code></td></tr>
-<tr><td> <code>∊</code> </td><td> <code>{(∾ð•ŠÂ¨)âŸ(0<≡ð•©)⥊ð•©}</code></td><td> <code>∊</code></td> </tr>
+<tr><td> <code>∊</code> </td><td> <code>{(∾ð•ŠÂ¨)âŸ(0<≡)⥊ð•©}</code> </td><td> <code>∊</code></td> </tr>
<tr><td> <code>⊃</code> </td><td colspan=2><code>⊑</code></td> </tr>
<tr><td> <code>â€</code> </td><td> </td><td> <code>{ð•©âŒ¾(ð•¨âЏ/)ð•¨â‰ âŠ¸â†‘0↑ð•©}</code></td></tr>
<tr><td> <code>∩</code> </td><td> </td><td> <code>∊/⊣</code></td> </tr>
@@ -118,8 +121,8 @@ The form `Fâ£G` (Power with a function right operand; Power limit) must be impl
<tr><td> <code>âŽ</code> </td><td colspan=2><code>•BQN</code></td> </tr>
<tr><td> <code>â•</code> </td><td colspan=2><code>•Fmt</code></td> </tr>
<tr><td> <code>⊥</code> </td><td> </td><td> <code>{+⟜(ð•¨âŠ¸Ã—)´⌽ð•©}</code> </td></tr>
-<tr><td> <code>⊤</code> </td><td> </td><td> <code>{>ð•¨|⌊∘÷`⌾⌽ð•¨Â«Ëœ<ð•©}</code></td></tr>
-<tr><td> <code>⌹</code> </td><td><code>Inverse</code> from <a href="https://github.com/mlochbaum/bqn-libs/blob/master/matrix.bqn">here</a></td><td><code>Solve</code></td></tr>
+<tr><td> <code>⊤</code> </td><td> </td><td> <code>{ð•¨|>⌊∘÷`⌾⌽ð•¨Â«Ëœ<ð•©}</code></td></tr>
+<tr><td> <code>⌹</code> </td><td><code>Inverse</code>, </td><td> <code>Solve</code> from <a href="https://github.com/mlochbaum/bqn-libs/blob/master/matrix.bqn">here</a></td></tr>
<tr><td> <code>⌷</code> </td><td> N/A </td><td> <code>âŠ</code></td> </tr>
</table>
diff --git a/doc/fromJ.md b/doc/fromJ.md
index ecca06f3..8c764432 100644
--- a/doc/fromJ.md
+++ b/doc/fromJ.md
@@ -14,13 +14,13 @@ A guide to help users of J get up to speed with BQN quickly. For a higher-level
BQN uses the [based array model](based.md), which is fundamentally different from J's flat array model. BQN uses non-array values such as characters and numbers, called "atoms", while in J every noun is an array. A BQN array can contain any values in any mixture, while a J array must be uniformly numbers, characters, or boxes (BQN doesn't use boxes).
-The J terms "atom" and "element" are used to mean different things by different authors. In BQN, an atom or rank-0 array is called a "unit", and the values contained in an array—which may or may not be arrays—are called "elements". Each element is contained in a 0-cell, or rank-0 subarray. BQN uses the term "major cell" for what J calls an "item" of an array: a cell with rank one less than that array. BQN shares the terms "list" and "table" for rank-1 and rank-2 arrays with J.
+The J terms "atom" and "element" are used to mean different things by different authors. In BQN, a rank-0 array or atom is called a "unit", and the values contained in an array—which may or may not be arrays—are called "elements". Each element is contained in a 0-cell, or rank-0 subarray. BQN uses the term "major cell" for what J calls an "item" of an array: a cell with rank one less than that array. BQN shares the terms "list" and "table" for rank-1 and rank-2 arrays with J.
BQN uses "[depth](depth.md)" rather than "boxing level". BQN gives atoms depth 0, so that the depth of a BQN array is one higher than the boxing level of the corresponding J array.
### Roles
-In J, the part of speech is an inherent property of a value, while in BQN it is determined by how the value is used in a particular expression, and can be different from the value's type. See [context-free grammar](context.md).
+In J, the part of speech is an inherent property of a value, while in BQN it's determined by how the value is used in a particular expression, and can be different from the value's type. See [context-free grammar](context.md).
| J part of speech | BQN role |
|---------------------|------------|
@@ -34,7 +34,7 @@ In J, the part of speech is an inherent property of a value, while in BQN it is
| J | BQN | Remarks
|-------------------|-------------|---------
| `NB.` | `#` |
-| `'` | `"` | `'` creates characters
+| `'` | `"` | `'` for character atoms
| `=.` and `=:` | `â†` and `↩` | `â†` to define; `↩` to modify
| `3 :…` or `{{…}}` | `{…}` |
| `:` | `;` | To separate function cases
@@ -45,7 +45,7 @@ In J, the part of speech is an inherent property of a value, while in BQN it is
| `[:` | `·` | Cap
| `assert.` | `!` |
-BQN's explicit functions and modifiers are called "blocks", and have a more sophisticated syntax than J; see [the documentation](block.md). BQN uses [lexical scope](lexical.md), and has no global variables. BQN also has a [list notation](arrayrepr.md#brackets) using `⟨⟩`.
+BQN's explicit functions and modifiers are called [blocks](block.md), and have a more sophisticated syntax than J. BQN uses [lexical scope](lexical.md), and has no global variables. BQN also has a [list notation](arrayrepr.md#brackets) using `⟨⟩`, and `[]` for higher-rank arrays.
## For reading
@@ -122,18 +122,18 @@ The tables below give approximate implementations of J primitives. J has a whole
| `*:` | `ט` | `¬∧`
| `-.` | `¬` | `¬∘∊/⊣`
| `-:` | `÷⟜2` | `≡`
-| `%.` | `Inverse` from [here](https://github.com/mlochbaum/bqn-libs/blob/master/matrix.bqn) | `Solve`
+| `%.` | `Inverse`, | `Solve` from [here](https://github.com/mlochbaum/bqn-libs/blob/master/matrix.bqn)
| `$` | `≢` | `⥊`
| `~.` | `â·` |
| `~:` | `∊` | `≠`
| `,` | `⥊` | `∾`
| `,.` | `⥊˘` | `∾˘`
-| `,:` | `â‰` |
+| `,:` | `â‰` | `â‰`
| `;` | `∾` | `∾⟜(<âŸ(1≥≡))`
| `#` | `≠` | `/`
| `#.` | `+˜⊸+˜´∘⌽` |
| `#:` | `⌽2\|⌊∘÷⟜2âŸ(↕1+·⌊2⋆â¼âŠ¢)` | ``{ð•¨\|1↓⌊∘÷`⌾⌽ð•¨âˆ¾<ð•©}``
-| `!` | `×´1+↕` | `-˜(+÷○(×´)⊢)1+↕∘⊣`
+| `!` | `×´1+↕` | `(-÷○(×´)1⊸+)⟜↕˜`
| `/:` | `â‹` | `â‹âЏâŠ`
| `\:` | `â’` | `â’⊸âŠ`
| `{` | `(<⟨⟩)<⊸∾⌜´⊢` | `âŠ`
diff --git a/doc/functional.md b/doc/functional.md
index 54989fae..cd7656ca 100644
--- a/doc/functional.md
+++ b/doc/functional.md
@@ -4,9 +4,9 @@
BQN boasts of its functional capabilities, including first-class functions. What sort of functional support does it have, and how can a BQN programmer exercise these and out themself as a Schemer at heart?
-First, let's be clear about what the terms we're using mean. A language has *first-class functions* when functions (however they are defined) can be used in all the same ways as "ordinary" values like numbers and so on, such as being passed as an argument or placed in a list. Lisp and JavaScript have first-class functions, C has unsafe first-class functions via function pointers, and Java 7 and APL don't have them as functions can't be placed in lists or used as arguments. This doesn't mean every operation is supported on functions: for instance, numbers can be added, compared, and sorted; while functions could perhaps be added to give a train, comparing or sorting them as functions (not representations) isn't computable, and BQN doesn't support any of the three operations when passing functions as arguments.
+First, let's be clear about what the terms we're using mean. A language has *first-class functions* when functions (however they are defined) can be used in all the same ways as "ordinary" values like numbers and so on, such as being passed as an argument or placed in a list. Lisp and JavaScript have first-class functions, and C has unsafe first-class functions via function pointers. Java 7 and APL don't have them, as functions can't be placed in lists or used as arguments. This doesn't mean every operation is supported on functions: for instance, numbers can be added, compared, and sorted; while functions could perhaps be added to give a train, comparing or sorting them as functions (not representations) isn't computable, and BQN doesn't support any of the three operations when passing functions as arguments.
-Traditionally, APL has worked around its lack of first-class functions with operators, that is, second-order functions. Arrays in APL are first class while functions are second class and operators are third class, and each class can act on the ones before it. However, the three-tier system has some obvious limitations that we'll discuss, and BQN removes these by making every type first class.
+Traditionally, APL has worked around its lack of first-class functions with operators, that is, second-order functions. Arrays in APL are first class while functions are second class and operators are third class, and each class can act on the ones above it. However, the three-tier system has some obvious limitations that we'll discuss, and BQN removes these by making every type first class.
<!--GEN
pl ↠<˘∘‿2⥊⟨
@@ -80,9 +80,9 @@ To ↠{
⟩
-->
-The term *functional programming* is more contentious, and has many meanings some of which can be vague. Here I use it for what might be called *first-class functional programming*, programming that makes significant use of first-class functions; in this usage, Scheme is probably the archetypal functional programming language. However, other definitions are also worth mentioning. APL is often called a functional programming language on the grounds that functions can be assigned and manipulated, and called recursively, all characteristics it shares with Lisp. I prefer the term *function-level programming* for this usage. A newer usage, which I call *pure functional programming*, restricts the term "function" to mathematical functions, which have no side effects, so that functional programming is programming with no side effects, often using monads to accumulate effects as part of arguments and results instead. Finally, *typed functional programming* is closely associated with pure functional programming and refers to languages influenced by type theory such as [Haskell](https://www.haskell.org/), [F#](https://fsharp.org/), and [Idris](https://www.idris-lang.org/) (the last of which even supports *[dependently-typed](https://en.wikipedia.org/wiki/Dependent_type) functional programming*, but I already said "finally" so we'll stop there). Of these, BQN supports first-class functional and function-level programming, allows but doesn't encourage pure functional programming, and does not support typed functional programming, as it's dynamically and not statically typed.
+The term *functional programming* is more contentious, and has many meanings some of which can be vague. Here I use it for what might be called *first-class functional programming*, programming that makes significant use of first-class functions; in this usage, Scheme is probably the archetypal functional programming language. However, other definitions are also worth mentioning. APL is often called a functional programming language on the grounds that functions can be assigned and manipulated, and called recursively, all characteristics it shares with Lisp. I prefer the term *function-level programming* for this usage. A newer usage, which I call *pure functional programming*, restricts the term "function" to mathematical functions, which have no side effects, so that functional programming is programming with no side effects, often using monads to accumulate effects as part of arguments and results instead. Finally, *typed functional programming* is closely associated with pure functional programming and refers to languages influenced by type theory such as [Haskell](https://www.haskell.org/), [F#](https://fsharp.org/), and [Idris](https://www.idris-lang.org/) (the last of which even supports *[dependently-typed](https://en.wikipedia.org/wiki/Dependent_type) functional programming*, but I already said "finally" so we'll stop there). Of these, BQN supports first-class functional and function-level programming, allows but doesn't encourage pure functional programming, and doesn't support typed functional programming, as it's dynamically and not statically typed.
-Another topic we are interested in is *lexical scoping* and *closures*. [Lexical scoping](lexical.md) means that the realm in which a variable exists is determined by its containing context (in BQN, the surrounding set of curly braces `{}`, if any) within the source code. A closure is really an implementation mechanism, but it's often used to refer to a property of lexical scoping that appears when functions defined in a particular block can be accessed after the block finishes execution. For example, they might be returned from a function or assigned to a variable outside of that function's scope. In this case the functions can still access variables in the original scope. I consider this property to be a requirement for a correct lexical scoping implementation, but it's traditionally not a part of APL: implementation might not have lexical scoping (for example, J and I believe [A+](https://aplwiki.com/wiki/A+) use static scoping where functions can't access variables in containing scopes) or might cut off the scope once execution ends, leading to value errors that one wouldn't predict from the rules of lexical scoping.
+Another topic we're interested in is *lexical scoping* and *closures*. [Lexical scoping](lexical.md) means that the realm in which a variable exists is determined by its containing context (in BQN, the surrounding set of curly braces `{}`, if any) within the source code. A closure is really an implementation mechanism, but it's often used to refer to a property of lexical scoping that appears when functions defined in a particular block can be accessed after the block finishes execution. For example, they might be returned from a function or assigned to a variable outside of that function's scope. In this case the functions can still access variables in the original scope. I consider this property to be a requirement for a correct lexical scoping implementation, but it's traditionally not a part of APL: implementation might not have lexical scoping (for example, J and K use static scoping where functions can't access variables in containing scopes) or might cut off the scope once execution ends, leading to value errors that one wouldn't predict from the rules of lexical scoping.
## Functions in APL
@@ -118,7 +118,7 @@ As with all functions, the result of `Lin` has a subject role. To use it as a fu
expLin ↠Lin exp
ExpLin 5
-A tricker but more compact method is to use the 1-modifier `{ð”½}`, as the input to a modifier can have a subject or function role but its output always has a function role.
+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
@@ -153,7 +153,7 @@ Another, and probably more common, use of arrays of functions is to apply severa
⟨√, 2⊸â‰, ⊢-⋆⟩ {ð•Žð•©}¨ 9
-The 2-modifier Choose (`â—¶`) relies on arrays of functions to… function. It's very closely related to Pick `⊑`, and in fact when the left operand and the elements of the right operand are all data there's no real difference: Choose returns the constant function `ð•—⊑ð•˜`.
+The 2-modifier [Choose](choose.md) (`â—¶`) relies on arrays of functions to… function. It's very closely related to [Pick](pick.md) `⊑`, and in fact when the left operand and the elements of the right operand are all data there's no real difference: Choose results in the constant function `ð•—⊑ð•˜`.
2â—¶"abcdef" "arg"
diff --git a/doc/glossary.md b/doc/glossary.md
index 6a0db156..cd68e6c9 100644
--- a/doc/glossary.md
+++ b/doc/glossary.md
@@ -32,32 +32,22 @@ BQN uses standard terminology for particular sets of numbers, with natural numbe
* **Real number** (more accurately, approximate doubly-extended real number): A number with no complex part.
* **Complex number**: A real number plus *i* (one of the square roots of -1) times another real number.
-## Roles
-
-* [**Syntactic role**](expression.md#syntactic-role): One of four possible types for an expression, which are determined by the expression itself and not outside context and describe how it interacts with other parts of the syntax.
-
-The possible roles are:
-* **Subject**: Can be passed to a function or modifier.
-* **Function**: Can be called on subjects or passed to a modifier.
-* **1-modifier**: Can be called on one subject or function.
-* **2-modifier**: Can be called on two subjects or functions.
-
## Arrays
* [**Array**](array.md): A multidimensional collection of values.
* [**Element**](array.md#elements): One of the values contained in an array.
* [**Axis**](array.md#rectangles): One dimension or direction in an array.
* [**Rank**](array.md#dimensions): The number of dimensions an array has.
-* [**Shape**](shape.md): The number of elements an array has along each dimension.
-* [**Length**](shape.md): The number of elements an array has along the first dimension, or 1 if it has rank 0.
+* [**Shape**](shape.md): The number of positions an array has along each dimension.
+* [**Length**](shape.md): The number of positions an array has along the first dimension, or 1 if it has rank 0.
* [**Depth**](depth.md): The greatest number of times an element can be selected from a value before reaching an atom.
* [**Fill**](fill.md): A "prototypical" array element used in certain operations; it's an inferred property of an array.
-* **Empty**: Having no elements. An array is empty if its shape contains 0.
-* [**Cell**](array.md#cells): An array containing all elements of the original array whose indices share a particular prefix.
+* [**Empty**](array.md#elements): Having no elements. An array is empty if its shape contains 0.
+* [**Cell**](array.md#cells): An array selected from a larger array, containing all elements whose indices share a particular prefix.
* [**k-Cell**](array.md#cells): A cell of rank *k*.
* [**Major cell**](array.md#cells): A cell with rank one less than the original array.
-* [**Agreement**](leading.md#leading-axis-agreement): The way elements are paired when a function maps over two arrays.
+* [**Agreement**](leading.md#leading-axis-agreement): The way elements are paired when mapping over two arrays together (for example by Each).
* [**Frame**](rank.md#frame-and-cells): A prefix of an array's shape, used for agreement with the Rank modifier.
* **Unit**: An array of rank 0, or an atom.
@@ -91,15 +81,6 @@ The possible roles are:
* **Error**: A condition that stops compilation or execution (see [assert](assert.md)).
* **Inferred property**: A property of a value that is derived by BQN based on constraints. If it can't be derived then the value won't have the property. Includes identity values, fill elements, and behavior of Undo and Under.
-## Namespaces
-
-* [**Namespace**](namespace.md): A container for variables, some of which are exposed as fields.
-* **Field**: One of the variables accessible from outside a namespace.
-* **Access**: To get the current value of a field from a namespace.
-* [**Export**](namespace.md#exports): Declare a variable to be accessible from the outside, that is, make it a field.
-* [**Object**](oop.md): Informal term for a namespace that holds mutable state.
-* [**Alias**](namespace.md#imports): A different "outside" name chosen for a field in a destructuring assignment.
-
## Tokens
* **Token formation** or tokenization: Splitting source code into a sequence of tokens.
@@ -113,14 +94,24 @@ The possible roles are:
* [**Character literal**](syntax.md#constants): A literal written with single quotes `''`, indicating a string.
* [**Null literal**](syntax.md#constants): The literal `@`, indicating the null character (code point 0).
-## Parsing
+## Grammar
-* **Parsing**: Analysis of the tokens of a program, which determines which actions will be taken to evaluate it.
-* [**Expression**](syntax.md#expressions): A piece of code that defines a (not necessarily constant) variable.
+* [**Expression**](syntax.md#expressions): A piece of code that describes the computation of a value.
* [**Nothing**](expression.md#nothing): A special value-like entity that comes from `·`, `ð•¨` in a function with no left argument, or a function called on nothing.
* **Statement**: An expression, nothing (`·`), or an export (`varâ‡`).
* [**Ligature**](arrayrepr.md#strands): The character `‿`.
* [**List notation**](arrayrepr.md#brackets): The angle brackets `⟨⟩` or ligatures used to indicate a list.
+* [**Array notation**](arrayrepr.md#high-rank-arrays): The square brackets `[]` used to form high-rank arrays.
+
+### Roles
+
+* [**Syntactic role**](expression.md#syntactic-role): One of four possible types for an expression, which are determined by the text of the expression, not outside context. The role describes how it interacts with other parts of the syntax.
+
+The possible roles are:
+* **Subject**: Can be passed to a function or modifier.
+* **Function**: Can be called on subjects or passed to a modifier.
+* **1-modifier**: Can be called on one subject or function.
+* **2-modifier**: Can be called on two subjects or functions.
## Assignment and scoping
@@ -135,7 +126,7 @@ The possible roles are:
## Blocks
* [**Block**](block.md): A syntactic element surrounded in curly braces `{}`, which encapsulates code.
-* [**Immediate block**](block.md#headerless-blocks): A block that is evaluated and returns a value immediately; it has a subject role.
+* [**Immediate block**](block.md#headerless-blocks): A block that's evaluated giving a result immediately; it has a subject role.
* **Block function**: A block defining a function.
* **Block modifier**: A block defining a 1- or 2-modifier.
* [**Immediate modifier**](block.md#operands): A modifier that's evaluated as soon as it receives its operands.
@@ -145,3 +136,12 @@ The possible roles are:
* [**Label**](block.md#short-headers): A header consisting of a single name.
* [**Predicate**](block.md#predicates): An expression followed by `?`, which acts as a condition for the body to continue running.
* [**Tacit**](tacit.md): Code that defines functions without using blocks.
+
+## Namespaces
+
+* [**Namespace**](namespace.md): A container for variables, some of which are exposed as fields.
+* **Field**: One of the variables accessible from outside a namespace.
+* **Access**: To get the current value of a field from a namespace.
+* [**Export**](namespace.md#exports): Declare a variable to be accessible from the outside, that is, make it a field.
+* [**Object**](oop.md): Informal term for a namespace that holds mutable state.
+* [**Alias**](namespace.md#imports): A different "outside" name chosen for a field in a destructuring assignment.
diff --git a/doc/group.md b/doc/group.md
index 7156c24b..030d2c97 100644
--- a/doc/group.md
+++ b/doc/group.md
@@ -2,8 +2,6 @@
# Group
-BQN replaces the Key operator from J or Dyalog APL, and [many forms of partitioning](https://aplwiki.com/wiki/Partition_representations), with a single (ambivalent) Group function `⊔`. This function is somewhat related to the K function `=` of the same name, but results in an array rather than a dictionary.
-
<!--GEN
Num ↠·Highlight •Repr
Str ↠·Highlight '"'(∾∾⊣)⊢
@@ -48,9 +46,13 @@ b ↠(0.4⌈0.2+≠¨zf) {∾"M vhv"∾¨FmtNum (0‿1‿1‿0‿1âŠd)×(⟨ð
⟩
-->
+The dyadic Group function places values into its result based on indices that tell where each should go. It's a little like a backwards version of [Select](select.md), but because any number of indices can point to the same place, result elements are groups, not single values from the argument.
+
+Group replaces the Key operator from J or Dyalog APL, and [many forms of partitioning](https://aplwiki.com/wiki/Partition_representations). It's related to the K function `=` of the same name, but results in an array rather than a dictionary.
+
## Definition
-Group operates on a list of atomic-number [indices](indices.md) `ð•¨` and an array `ð•©`, treated as a list of its major cells, to produce a list of groups, each containing some of the cells from `ð•©`. The two arguments have the same length, and each cell in `ð•©` is paired with the index in `ð•¨` at the same position, which indicates which result group should include that cell.
+Group operates on a list of atomic-number [indices](indices.md) `ð•¨` and an array `ð•©`, treated as a list of its [major cells](array.md#cells), to produce a list of groups, each containing some of the cells from `ð•©`. The two arguments have the same length, and each cell in `ð•©` is paired with the index in `ð•¨` at the same position, to indicate which result group should include that cell.
0‿1‿2‿0‿1 ≠"abcde" # Corresponding indices and values
@@ -58,11 +60,11 @@ Group operates on a list of atomic-number [indices](indices.md) `ð•¨` and an ar
A few extra options can be useful in some circumstances. First, an "index" of `¯1` in `ð•¨` indicates that the corresponding cell should be dropped and not appear in the result. Second, `ð•¨` is allowed to have an extra element after the end, which gives a minimum length for the result: otherwise, the result will be just long enough to accomodate the highest index in `ð•¨` (it might seem like the last element should be treated like an index, making the minimum length one higher, but the length version usually leads to simpler arithmetic).
- 0‿¯1‿2‿2‿¯1 ⊔ "abcde" # Drop c and e
+ 0‿¯1‿2‿2‿¯1 ⊔ "abcde" # Drop b and e
0‿1‿2‿2‿1‿6 ⊔ "abcde" # Length-6 result
-A third extension is that `ð•¨` doesn't really have to be a list: if not, then it groups `-=ð•¨`-cells of `ð•©` instead of just `¯1`-cells. These cells are placed in index order. This extension isn't compatible with the second option from above, because it's usually not possible to add just one extra element to a non-list array. One usage is to group the diagonals of a table. See if you can figure out how the code below does this.
+A third extension is that `ð•¨` doesn't really have to be a list: if not, then it groups `-=ð•¨`-cells of `ð•©` instead of just `¯1`-cells. These cells are placed in index order. This extension isn't compatible with the second option from above, because it's usually not possible to add just one extra element to a non-list array. One usage is to group the diagonals of a table. See if you can find how the code below does this.
⊢ a ↠'a'+⥊⟜(↕×´)3‿5
@@ -71,7 +73,7 @@ A third extension is that `ð•¨` doesn't really have to be a list: if not, then
For a concrete example, we might choose to group a list of words by length. Within each group, cells maintain the ordering they had in the list originally.
phrase ↠"BQN"‿"uses"‿"notation"‿"as"‿"a"‿"tool"‿"of"‿"thought"
- â‰Ë˜ ≠¨⊸⊔ phrase
+ â‰Ë˜ ≠¨⊸⊔ phrase # â‰Ë˜ to format vertically
(Could we define `phrase` more easily? See [below](#partitioning).)
@@ -97,35 +99,17 @@ But `ð•©` can also be a list of numeric arrays. In this case the indices `↕âˆ
### Multidimensional grouping
-Dyadic Group allows the right argument to be grouped along multiple axes by using a nested left argument. In this case, the left argument must be a list of numeric lists, and the result has rank `≠ð•¨` while its elements—as always—have the same rank as `ð•©`. The result shape is `1+⌈´¨ð•¨`, while the shape of element `i⊑ð•¨âŠ”ð•©` is `i+´∘=¨ð•¨`. If every element of `ð•¨` is sorted ascending and contains only non-negative numbers, we have `ð•©â‰¡âˆ¾ð•¨âŠ”ð•©`, that is, [Join](join.md#join) is the inverse of Partition.
+Dyadic Group allows the right argument to be grouped along multiple axes by using a nested left argument. In this case, `ð•¨` must be a list of numeric lists, and the result has rank `≠ð•¨` while its elements—as always—have the same rank as `ð•©`. The result shape is `1+⌈´¨ð•¨`, while the shape of element `i⊑ð•¨âŠ”ð•©` is `i+´∘=¨ð•¨`. If every element of `ð•¨` is sorted ascending and has no ¯1s, we have `ð•©â‰¡âˆ¾ð•¨âŠ”ð•©`, that is, [Join](join.md#join) is the inverse of partitioning.
Here we split up a rank-2 array into a rank-2 array of rank-2 arrays. Along the first axis we simply separate the first pair and second pair of rows—a partition. Along the second axis we separate odd from even indices.
⟨0‿0‿1‿1,0‿1‿0‿1‿0‿1‿0⟩ ⊔ (10×↕4)+⌜↕7
-Each group `i⊑ð•¨âŠ”ð•©` is composed of the cells `j<¨⊸âŠð•©` such that `i≢j⊑¨ð•¨`. The groups retain their array structure and ordering along each argument axis. Using multidimensional Replicate we can say that `i⊑ð•¨âŠ”ð•©` is `(i=ð•¨)/ð•©`.
-
-## Properties
-
-Group is closely related to the [inverse of Indices](replicate.md#inverse), `/â¼`. In fact, inverse Indices called on the index argument gives the length of each group:
-
- ≠¨⊔ 2‿3‿1‿2
- /â¼âˆ§ 2‿3‿1‿2
-
-A related fact is that calling Indices on the result lengths of Group sorts all the indices passed to Group (removing any ¯1s). This is a kind of counting sort.
-
- /≠¨⊔ 2‿3‿1‿¯1‿2
-
-Called dyadically, Group sorts the right argument according to the left and adds some extra structure. If this structure is removed with [Join](join.md#join), Group can be thought of as a kind of sorting.
-
- ∾ 2‿3‿1‿¯1‿2 ⊔ "abcde"
- 2‿3‿1‿¯1‿2 {Fâ†(0≤ð•¨)⊸/ â‹„ ð•¨â‹âЏâŠâ—‹Fð•©} "abcde"
-
-Group can even be implemented with the same [techniques](../implementation/primitive/sort.md#counting-and-bucket-sort) as a bucket sort, making it branchless and fast.
+Each group `i⊑ð•¨âŠ”ð•©` is composed of the cells `j<¨⊸âŠð•©` such that `i≢j⊑¨ð•¨`. The groups retain their array structure and ordering along each argument axis. Using multidimensional [Replicate](replicate.md) we can say that `i⊑ð•¨âŠ”ð•©` is `(i=ð•¨)/ð•©`.
## Applications
-The obvious application of Group is to group some values according to a known or computed property. If this property isn't a natural number, it can be turned into one using [Classify](selfcmp.md#classify) (`âŠ`), which numbers the unique values in its argument by first occurrence.
+The most direct application of Group is to group some values according to a known or computed property. If this property isn't a natural number, it can be turned into one using [Classify](selfcmp.md#classify) (`âŠ`), which numbers the unique values in its argument by first occurrence.
ln ↠"Phelps"‿"Latynina"‿"Bjørgen"‿"Andrianov"‿"Bjørndalen"
co ↠"US" ‿"SU" ‿"NO" ‿"SU" ‿"NO"
@@ -143,7 +127,7 @@ However, this solution will fail if there are trailing keys with no values. To f
### Partitioning
-In examples we have been using a list of strings stranded together. Often it's more convenient to write the string with spaces, and split it up as part of the code. In this case, the index corresponding to each word (that is, each letter in the word) is the number of spaces before it. We can get this number of spaces from a Plus-[Scan](scan.md) on the boolean list which is 1 at each space.
+Previous examples have used lists of strings stranded together. Often it's more convenient to write the string with spaces, and split it up as part of the code. In this case, the index corresponding to each word (that is, each letter in the word) is the number of spaces before it. We can get this number of spaces from a Plus-[Scan](scan.md) on the boolean list which is 1 at each space.
' '(+`∘=⊔⊢)"BQN uses notation as a tool of thought"
@@ -151,7 +135,7 @@ To avoid including spaces in the result, we should change the result index at ea
' '((⊢-˜¬×+`)∘=⊔⊢)"BQN uses notation as a tool of thought"
-A function with structural [Under](under.md), such as `` {¯1¨⌾(ð•©âЏ/)+`ð•©} ``, would also work.
+A function with [Under](under.md), such as `` {¯1¨⌾(ð•©âЏ/)+`ð•©} ``, would also work.
In other cases, we might want to split on spaces, so that words are separated by any number of spaces, and extra spaces don't affect the output. Currently our function makes a new word with each space:
@@ -160,7 +144,27 @@ In other cases, we might want to split on spaces, so that words are separated by
Trailing spaces are ignored because Group with equal-length arguments never produces trailing empty groups—to intentionally include them you'd replace `=` with `(=∾0˙)`. But in string processing we probably want to avoid empty words anywhere. To make this happen, we should increase the word index only once per group of spaces. We can do this by applying Plus Scan to a list that is 1 only for a space with no space before it. This list is produced using [Shift Before](shift.md) to get a list of previous elements. To treat the first element as though it's before a space (so that leading spaces have no effect rather than creating an initial empty group), we shift in a 1.
(⊢â‰1⊸»<⊢) ' '=" string with spaces " # All, then filtered, spaces
+
â‰âŸœ(⊢-˜¬×·+`1⊸»<⊢)' '=" string with spaces " # More processing
+
' '((⊢-˜¬×·+`1⊸»<⊢)∘=⊔⊢)" string with spaces " # Final result
' '((¬-˜⊢×·+`»⊸>)∘≠⊔⊢)" string with spaces " # Slightly shorter
+
+## Group and sorting
+
+Group is closely related to the [inverse of Indices](replicate.md#inverse), `/â¼`. Calling that function on the index argument gives the length of each group:
+
+ ≠¨⊔ 2‿3‿1‿2
+
+ /â¼âˆ§ 2‿3‿1‿2
+
+A related fact is that calling Indices on the result lengths of Group sorts all the indices passed to Group (removing any ¯1s). This is a kind of counting sort.
+
+ /≠¨⊔ 2‿3‿1‿¯1‿2
+
+Called dyadically, Group sorts the right argument according to the left and adds some extra structure. If this structure is removed with [Join](join.md#join), Group can be thought of as a kind of sorting.
+
+ ∾ 2‿3‿1‿2 ⊔ "abcd"
+
+ 2‿3‿1‿2 â‹âŠ¸âŠ "abcd"
diff --git a/doc/map.md b/doc/map.md
index 3ec1b6ce..d8294315 100644
--- a/doc/map.md
+++ b/doc/map.md
@@ -64,7 +64,9 @@ A nice way to examine what's being applied here is to make an argument where eac
The applications are performed in index order: index `…0‿0`, then `…0‿1`, `…0‿2` and so on, until `…1‿0`. This can affect a program where the operand has side effects, such as the following one that appends its argument to `o`.
- oâ†âŸ¨âŸ© â‹„ {o∾⟜<↩ð•©}¨ "index"â‰"order" â‹„ o
+ ["index","order"]
+
+ oâ†âŸ¨âŸ© â‹„ {o∾⟜<↩ð•©}¨ ["index","order"] â‹„ o
When an array is displayed, index order is the same as the top-to-bottom, left-to-right reading order of English. It's also the same as the ordering of [Deshape](reshape.md#deshape)'s result, so that here `o` ends up being `⥊ð•©`. The dyadic cases described in the following sections will also have a defined evaluation order, but it's not as easy to describe it in terms of the arguments: instead, the *result* elements are produced in index order.
@@ -103,7 +105,7 @@ When an array is displayed, index order is the same as the top-to-bottom, left-t
The Table modifier applies its operand function to every possible combination of one element from `ð•¨` and one from `ð•©`, sort of like a structure-preserving and function-applying [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product). Below, it combines a length-3 list and a length-5 list into a shape `3‿5` table.
- "ABC" â‰âŒœ "01234"
+ "ABC" ⋈⌜ "01234"
Its name comes from the "multiplication table" or "times table" often used to teach arithmetic, and with it you can easily make such a table, by repeating the same argument with [Self](swap.md) (`˜`):
@@ -111,9 +113,9 @@ Its name comes from the "multiplication table" or "times table" often used to te
The arguments don't have to be lists (that is, rank 1). There's no restriction on their shapes at all! Much like the result shape is `m‿n` if `ð•¨` is a list of length `m` and `ð•©` is a list of length `n`, the result shape for an array `ð•¨` of shape `r` and `ð•©` of shape `s` is `r∾s`.
- "A "‿"B " ∾⌜ "the"‿"first"‿"row"â‰"and"‿"the"‿"second"
+ "A "‿"B " ∾⌜ ["the"‿"first"‿"row","and"‿"the"‿"second"]
- ≢ "A "‿"B " ∾⌜ "the"‿"first"‿"row"â‰"and"‿"the"‿"second"
+ ≢ "A "‿"B " ∾⌜ ["the"‿"first"‿"row","and"‿"the"‿"second"]
Except for the more sophisticated shape, this result is exactly what you'd get if you deshaped each argument to a list. In each case, every element of `ð•¨` is visited in turn, and each time the element is paired with every element of `ð•©`.
@@ -142,24 +144,24 @@ Except for the more sophisticated shape, this result is exactly what you'd get i
Given two arguments of matching shapes, Each performs what's sometimes called a "zip", matching each element of `ð•¨` to the corresponding element of `ð•©`.
- "ABCD" â‰Â¨ "0123"
+ "ABCD" ⋈¨ "0123"
This makes for a lot fewer applications than Table. Only the diagonal elements from Table's result are seen, as we can check with [Reorder Axes](transpose.md#reorder-axes).
- 0‿0 ≠"ABCD" â‰âŒœ "0123"
+ 0‿0 ≠"ABCD" ⋈⌜ "0123"
If the argument lengths don't match then Each gives an error. This differs from zip in many languages, which drops elements from the longer argument (this is natural for linked lists). This flexibility is rarely wanted in BQN, and having an error right away saves debugging time.
- "ABC" â‰Â¨ "01234"
+ "ABC" ⋈¨ "01234"
Arguments can have any shape as long as the axis lengths match up. As with Table, the result elements don't depend on these shapes but the result shape does.
- [20‿30‿10,50‿40‿60] +⟜↕¨ 2‿1‿0â‰3‿2‿1
+ [20‿30‿10,50‿40‿60] +⟜↕¨ [2‿1‿0,3‿2‿1]
But arguments don't have to have exactly the same shape: just the same length along corresponding axes. These axes are matched up by [leading axis agreement](leading.md#leading-axis-agreement), so that one argument's shape has to be a prefix of the other's. With equal ranks, the shapes do have to match as we've seen above.
- ≢ (0‿2‿6⥊@) â‰Â¨ 0‿1⥊0 # Too small
+ ≢ (0‿2‿6⥊@) ⋈¨ 0‿1⥊0 # Too small
- ≢ (0‿2‿6⥊@) â‰Â¨ 0‿3⥊0 # Too large
+ ≢ (0‿2‿6⥊@) ⋈¨ 0‿3⥊0 # Too large
- ≢ (0‿2‿6⥊@) â‰Â¨ 0‿2⥊0 # Just right
+ ≢ (0‿2‿6⥊@) ⋈¨ 0‿2⥊0 # Just right