diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2022-06-04 17:40:31 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2022-06-04 17:40:31 -0400 |
| commit | 7e5d0fcc39fd8a683fc7010af064849b454b432b (patch) | |
| tree | 272f7003486c3e94c41e8eec155f4095c47e6661 | |
| parent | cd0f461eee93367459dd82a29dd148fff75e5ec6 (diff) | |
Further editing
| -rw-r--r-- | doc/glossary.md | 2 | ||||
| -rw-r--r-- | doc/lexical.md | 12 | ||||
| -rw-r--r-- | doc/logic.md | 40 | ||||
| -rw-r--r-- | doc/map.md | 14 | ||||
| -rw-r--r-- | doc/match.md | 12 | ||||
| -rw-r--r-- | doc/namespace.md | 26 | ||||
| -rw-r--r-- | doc/transpose.md | 2 | ||||
| -rw-r--r-- | docs/doc/glossary.html | 2 | ||||
| -rw-r--r-- | docs/doc/lexical.html | 12 | ||||
| -rw-r--r-- | docs/doc/logic.html | 31 | ||||
| -rw-r--r-- | docs/doc/map.html | 19 | ||||
| -rw-r--r-- | docs/doc/match.html | 12 | ||||
| -rw-r--r-- | docs/doc/namespace.html | 22 | ||||
| -rw-r--r-- | docs/doc/transpose.html | 2 |
14 files changed, 106 insertions, 102 deletions
diff --git a/doc/glossary.md b/doc/glossary.md index 7f8d4bf4..14968154 100644 --- a/doc/glossary.md +++ b/doc/glossary.md @@ -96,7 +96,7 @@ The possible roles are: * **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**: A different "outside" name chosen for a field in a destructuring assignment. +* [**Alias**](namespace.md#imports): A different "outside" name chosen for a field in a destructuring assignment. ## Tokens diff --git a/doc/lexical.md b/doc/lexical.md index 3183f7f3..b6ca828d 100644 --- a/doc/lexical.md +++ b/doc/lexical.md @@ -4,7 +4,7 @@ BQN uses lexical scope, like most modern functional programming languages including Javascript, Scheme, and Julia, and like Dyalog APL's dfns (tradfns are dynamically scoped). This document describes how lexical scoping works, and a few small details relevant to BQN's version of it. -In short, every [block](block.md) is a separate scope that can refer to identifiers in containing scopes. When evaluated, the block makes a variable for each identifier defined in it (including arguments and operands). The blocks that it contains will now access these variables. In the first level of a block, variables must be defined before they can be used, but in child blocks, a variable can be used regardless of where it's defined, as long as the definition is evaluated before the child block is. +In short, every [block](block.md) is a separate scope, but can use identifiers in containing scopes. Each time it's evaluated, the block makes a variable for each identifier defined in it (including arguments and operands). The blocks that it contains might access these variables. At the top level of a block, identifiers must be defined before they can be used, but in child blocks, an identifier can be used even if it's defined later, as long as that use isn't evaluated before the definition can set the variable value. ## Scopes @@ -18,7 +18,7 @@ Scoping is a mechanism that allows the same variable name to refer to different Above, the scope of the first `a` is the entire program, while the scope of the second `a` is limited to the body of `F`. So one form of context is that a name might mean different things depending on which block contains it. But even the exact same instance of a name in the source code might mean multiple things! A second kind of context is which evaluation of a block uses the name. -Without this ability BQN would be pretty limited: for example, an [object](oop.md)'s fields are variables. If the variable value didn't depend on what object contained it, there could effectively only be one instance of each object! While it's needed all the time, the most direct way to demonstrate one name meaning multiple things is with recursion. The (fragile) function below labels each element in a nested list structure with its index in the list containing it. +Without this ability BQN would be pretty limited: for example, an [object](oop.md)'s fields are variables. If the variable value didn't depend on what object contained it, there could effectively only be one instance of each object! It's not the most common use case, but recursion is the most direct way to demonstrate a name meaning multiple things at once. The (fragile) function below labels each element in a nested list structure with its index in the list containing it. Label ← { i←↕≠𝕩 ⋄ i ≍ 𝕊⍟=¨ 𝕩 } @@ -30,7 +30,7 @@ These examples probably work like you expect—they're meant to highlight the fe ## Visibility -A scope can view and modify (with `↩`) variables in other scopes that contain it. We say these variables are visible in the inner scopes. Variables at the top level of a program are visible to all the code in that program, so that we might call them "global". That would be a little misleading though, because for example each file is an entire program, so if one file is imported from another then it can't read the first file's variables. +A scope can view and [modify](expression.md#assignment) (with `↩`) variables in other scopes that contain it. We say these variables are *visible* in the inner scopes. Variables at the top level of a program are visible to all the code in that program, so that we might call them "global". That's somewhat misleading, because for example each file is an entire program, so if one file is imported from another then it can't read the first file's variables. counter ← 0 inc ← 6 @@ -96,7 +96,7 @@ Each result keeps its own counter and the different copies don't interfere with Each counter function has access to the environment containing its `counter` and `inc`, even though the block that created that environment (`_makeCount`) has finished execution—it must have finished, since we are now using the function it returns on the last line. There's nothing particularly weird about this; just because a block creates an environment when it starts doesn't mean it has to destroy it when it finishes. From the mathematical perspective, it's easiest to say the environment exists forever, but a practical implementation will perform garbage collection to free environments that are no longer reachable. -Since a function like `C1_4` maintains access to all the variables it needs to run, we say it *encloses* those variables, and call it a *closure*. It doesn't need to modify them. For example, even the following definition of `stdDev` is a closure. +Since a function like `C1_4` maintains access to all the variables it needs to run, we say it *encloses* those variables, and call it a *closure*. It doesn't need to modify them. For example, the following definition of the theoretical standard deviation function `StdDev` is also a closure. stdDev ← { # Arithmetic mean @@ -124,7 +124,7 @@ How does an environment know which of the many environments corresponding to the ## Mutation -The value of a variable can be modified with `↩`. It's similar to definition `←` in that it sets the value of the variable, but the way it interacts with scoping is completely different. Defining creates a new variable in the current scope, and modifying refers to an existing variable in the current scope or a parent. In scoping terms, modifying is more like an ordinary variable reference than a definition. +The value of a variable can be modified with `↩`. It's similar to definition `←` in that it sets the value of the variable, but the way it interacts with scoping is completely different. Definition creates a new variable in the current scope, and modification refers to an existing variable in the current scope or a parent. In scoping terms, a modification is more like an ordinary variable reference than a definition. When a variable's modified, functions with access to it see the new value. They have access to the variable, not any particular value that it has. @@ -135,7 +135,7 @@ When a variable's modified, functions with access to it see the new value. They factor ↩ 5 Mul 6 # A new result -Only 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 a constant in each environment that contains it (not necessarily across environments). That is, constant once it's defined: it's still possible to get an error if the variable is accessed before being defined. +Only 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 a constant in each environment that contains it (not necessarily across environments). 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 } ⋄ a←4 } diff --git a/doc/logic.md b/doc/logic.md index 080e54f1..89312e92 100644 --- a/doc/logic.md +++ b/doc/logic.md @@ -2,26 +2,12 @@ # Logic functions: And, Or, Not (also Span) -BQN uses the mathematical symbols `∧` and `∨` for logical *and* and *or*, and `¬` for *not* (APL's `~` is discarded since it looks like `˜`, and is less common in mathematics today). These functions are arithmetically extended to apply to all numbers. In the case of Not, that means the linear function `1⊸-`. The two-argument functions have bilinear extensions: And is identical to Times (`×`), while Or is `×⌾¬`, following De Morgan's laws (other ways of obtaining a function for Or give an equivalent result—there is only one bilinear extension). +BQN uses the mathematical symbols `∧` and `∨` for logical *and* and *or*, and `¬` for *not* (APL's `~` is discarded since it looks like `˜`, and is less common in mathematics today). That is, on two booleans `∧` is 1 if both are 1, and `∨` is if either is 1. `¬` flips its argument, returning 1 if the argument is 0 and 0 if it's 1. The logic functions are also considered [arithmetic](arithmetic.md) and thus are [pervasive](arithmetic.md#pervasion). -If the arguments are probabilities of independent events, then an extended function gives the probability of the boolean function on their outcomes (for example, if *A* occurs with probability `a` and *B* with probability `b` independent of *A*, then *A* or *B* occurs with probability `a∨b`). These extensions have also been used in complexity theory, because they allow mathematicians to transfer a logical circuit from the discrete to the continuous domain in order to use calculus on it. +These boolean functions are arithmetically extended to apply to all numbers. Not returns `1-𝕩`, And returns `𝕨×𝕩`, and Or does a more complicated computation `𝕨×⌾¬𝕩`. Both valences of `¬` are equivalent to the fork `1+-`. The dyadic valence, called "Span", computes the number of integers in the range from `𝕩` to `𝕨`, inclusive, when both arguments are integers and `𝕩≤𝕨` (note the reversed order, which is used for consistency with subtraction). This function has many uses, and in particular is relevant to the [Windows](windows.md) function. -These functions are considered [arithmetic](arithmetic.md) functions and thus are [pervasive](arithmetic.md#pervasion). - -## Definitions - -We define: - - Not ← 1+- # also Span - And ← × - Or ← ×⌾¬ - -Note that `¬⁼ ←→ ¬`, since when applying `¬` twice the first added 1 will be negated but the second won't; the two 1s cancel leaving two subtractions, and `-⁼ ←→ -`. An alternate definition of Or that matches the typical formula from probability theory is - - Or ← +-× - ## Examples We can form truth [tables](map.md#table) including the non-integer value one-half: @@ -34,11 +20,21 @@ We can form truth [tables](map.md#table) including the non-integer value one-hal As with logical And and Or, any value and 0 is 0, while any value or 1 is 1. The other boolean values give the identity values for the two functions: 1 and any value gives that value, as does 0 or the value. -## Why not GCD and LCM? +## Definitions -APL provides [GCD](https://aplwiki.com/wiki/GCD) and [LCM](https://aplwiki.com/wiki/LCM) as extensions of And and Or, while BQN doesn't make these functions primitives. The main reason for omitting them functions is that they are complicated and, when applied to real or complex numbers, require a significant number of design decisions where there is no obvious choice (for example, whether to use comparison tolerance). On the other hand, these functions are fairly easy to implement, which allows the programmer to control the details, and also add functionality such as the extended GCD. Possible implementations for GCD and LCM are shown in [bqncrate](https://mlochbaum.github.io/bqncrate) ([GCD](https://mlochbaum.github.io/bqncrate/?q=gcd), [LCM](https://mlochbaum.github.io/bqncrate/?q=lcm)). +We define -A secondary reason is that the GCD falls short as an extension of Or, because its identity value 0 is not total. `0∨x`, for a real number `x`, is actually equal to `|x` and not `x`: for example, `0∨¯2` is `2` in APL. This means the identity `0∨x ←→ x` isn't reliable in APL. + Not ← 1+- # also Span + And ← × + Or ← ×⌾¬ + +using a [train](train.md) for Not and [Under](under.md) for Or. The latter expands to `Or ← ¬∘×○¬`, since Not is a self-inverse `¬⁼ ←→ ¬`: when applying `¬` twice the first added 1 will be negated but the second won't; the two 1s cancel leaving two subtractions, and `-⁼ ←→ -`. An alternate definition of Or that matches the typical formula from probability theory is + + Or ← +-× + +The logic functions are extended to all numbers by making them linear in every argument. In the case of Not, that means the linear function `1⊸-`. The two-argument functions have bilinear extensions: And is identical to Times (`×`), while Or is `×⌾¬`, following De Morgan's laws (other ways of obtaining a function for Or give an equivalent result—there is only one bilinear extension). + +If the arguments are probabilities of independent events, then an extended function gives the probability of the boolean function on their outcomes. For example, if *A* occurs with probability `a` and *B* with probability `b` independent of *A*, then at least one of *A* or *B* occurs with probability `a∨b`. These extensions have also been used in complexity theory, because they allow mathematicians to transfer a logical circuit from the discrete to the continuous domain in order to use calculus on it. ## Identity values @@ -47,3 +43,9 @@ It's common to apply a [fold](fold.md) `∧´` or `∨´` to a list (checking wh It's not hard to prove that the bilinear extensions have the identity values we want. Of course `1∧x` is `1×x`, or `x`, and `0∨x` is `0×⌾¬x`, or `¬1׬x`, giving `¬¬x` or `x` again. Both functions are commutative, so these values are identities on the right as well. Other logical identities do not necessarily hold. For example, in boolean logic And distributes over Or and vice-versa: `a∧b∨c ←→ (a∧b)∨(a∧c)`. But substituting `×` for `∧` and `+-×` for `∨` we find that the left hand side is `(a×b)+(a×c)+(a×b×c)` while the right gives `(a×b)+(a×c)+(a×b×a×c)`. These are equivalent for arbitrary `b` and `c` only if `a=a×a`, that is, `a` is 0 or 1. In terms of probabilities the difference when `a` is not boolean is caused by failure of independence. On the left hand side, the two arguments of every logical function are independent. On the right hand side, each pair of arguments to `∧` are independent, but the two arguments to `∨`, `a∧b` and `a∧c`, are not. The relationship between these arguments means that logical equivalences no longer apply. + +## Why not GCD and LCM? + +APL provides [GCD](https://aplwiki.com/wiki/GCD) and [LCM](https://aplwiki.com/wiki/LCM) as extensions of And and Or, while BQN doesn't make these functions primitives. The main reason for omitting them functions is that they are complicated and, when applied to real or complex numbers, require a significant number of design decisions where there's no obvious choice (for example, whether to use comparison tolerance). On the other hand, these functions are fairly easy to implement, which allows the programmer to control the details, and also add functionality such as the extended GCD. Possible implementations for GCD and LCM are shown in [bqncrate](https://mlochbaum.github.io/bqncrate) ([GCD](https://mlochbaum.github.io/bqncrate/?q=gcd), [LCM](https://mlochbaum.github.io/bqncrate/?q=lcm)). + +A secondary reason is that the GCD falls short as an extension of Or, because its identity value 0 is not total. `0∨x`, for a real number `x`, is actually equal to `|x` and not `x`: for example, `0∨¯2` is `2` in APL. This means the identity `0∨x ←→ x` isn't reliable in APL. @@ -4,7 +4,7 @@ Mapping a function over an array means to call it on each element of that array, creating an array of results. It's also possible to map over two arrays, applying the function to various choices of one element from each, but there's no longer a single correct way to iterate over these elements. -BQN has two 1-modifiers to map over arrays: Each (`¨`) and Table (`⌜`). On two arguments, Table applies its operand to all combinations of elements while Each creates a one-to-one or one-to-many matching. Since they apply to elements, these modifiers are different from Cells (`˘`) or its generalization Rank (`⎉`), which apply the function to array cells. The modifier [Depth](depth.md#the-depth-modifier) (`⚇`) is a generalization of Each, so that `¨` is `⚇¯1`; however, it can't be used to implement Table without some additional array operations. +As a result, BQN has two 1-modifiers to map over arrays: Each (`¨`) and Table (`⌜`). On two arguments, Table applies its operand to all combinations of elements while Each creates a one-to-one or one-to-many matching. Since they apply to elements, these modifiers are different from [Cells](rank.md#cells) (`˘`) or its generalization [Rank](rank.md#rank) (`⎉`), which apply the function to array cells. The modifier [Depth](depth.md#the-depth-modifier) (`⚇`) is a generalization of Each, so that `¨` is `⚇¯1`; however, it can't be used to implement Table without some additional array operations. ## One-argument mapping @@ -105,7 +105,7 @@ The Table modifier applies its operand function to every possible combination of "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 (`˜`): +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) (`˜`): ×⌜˜ 1+↕6 @@ -144,11 +144,11 @@ Given two arguments of matching shapes, Each performs what's sometimes called a "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 [Transpose](transpose.md). +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" -If the argument lengths don't match then Each gives an error. This contrasts with 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. +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" @@ -156,10 +156,10 @@ Arguments can have any shape as long as the axis lengths match up. As with Table (>⟨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 according to the [leading axis convention](leading.md), 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. +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‿2⥊0 # Just right + ≢ (0‿2‿6⥊@) ≍¨ 0‿3⥊0 # Too large -Leading axis agreement is described further [here](leading.md#leading-axis-agreement). + ≢ (0‿2‿6⥊@) ≍¨ 0‿2⥊0 # Just right diff --git a/doc/match.md b/doc/match.md index 9d102238..dddcd50d 100644 --- a/doc/match.md +++ b/doc/match.md @@ -17,11 +17,11 @@ Match always gives the same result as [Equals](arithmetic.md#comparisons) (`=`) Match compares arrays based on their fundamental properties—[shape](shape.md) and elements—and not the [fill element](fill.md), which is an inferred property. Since it can be computed differently in different implementations, using the fill element in Match could lead to some confusing results. Even if the implementation doesn't define a fill for `'a'‿'b'‿'c'`, it should still be considered to match `"abc"`. -To give a precise definition, two arrays are considered to match if they have the same shape and all corresponding elements from the two arrays match. Every array has a finite [depth](depth.md) so this recursive definition always ends up comparing non-arrays, or atoms. An array never matches an atom, so the result if only one argument is an atom is `0`. The interesting case is when both arguments are atoms, discussed below. +To give a precise definition, two arrays are considered to match if they have the same shape and all corresponding elements from the two arrays match. Every array has a finite [depth](depth.md), so this recursive definition always ends up comparing non-arrays, or atoms. And because an array never matches an atom, the result if only one argument is an atom is `0`. The interesting case is when both arguments are atoms, discussed below. ## Atomic equality -Atoms in BQN have six possible [types](types.md): number, character, function, 1-modifier, 2-modifier, and namespace. Equality is not allowed to fail for any two arguments, so it needs to be defined on all of these types. +Atoms in BQN have six possible [types](types.md): number, character, function, 1-modifier, 2-modifier, and namespace. Equality testing isn't allowed to fail for any two arguments, so it needs to be defined on all of these types. Starting with the easiest rules, values with different types are never equal to each other. @@ -33,12 +33,12 @@ Two characters are equal when they have the same code point. Numeric equality de 1.25 = 1 + 0.25 -Mutable types are more difficult. Here there are three cases: +Operations and namespaces are more difficult. Here there are three cases: - Primitives are equal if they have the same glyph. - Compound functions or modifiers are split into components. - Block instances or namespaces are equal if they are the same instance. -The first two are fairly similar to how numbers and arrays work. Primitives and compounds like trains, or modifiers with bound operands, are immutable, so they are defined purely by what components they contain. +The first two are fairly similar to how numbers and arrays work. Primitives and compounds like trains, or modifiers with bound operands, are immutable, so they're defined purely by what components they contain. ⟨+,-,×⟩ = ⟨+,-,÷⟩ @@ -58,7 +58,7 @@ The final point above about block instances is subtler. An instance of a block f G 8 F 5 # Another result—the definition of insanity! -(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. When we apply `G`, the result of `F` might change, but so does `F1`! This effect is called [aliasing](https://en.wikipedia.org/wiki/Aliasing_(computing)). +(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](tacit.md) 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](https://en.wikipedia.org/wiki/Aliasing_(computing)). F1 ← F {𝕏 6}¨ F‿F1 @@ -66,7 +66,7 @@ The final point above about block instances is subtler. An instance of a block f G 3 {𝕏 6}¨ F‿F1 -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. Comparison tells you whether two blocks are the same. +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 diff --git a/doc/namespace.md b/doc/namespace.md index 5b7f67e5..896b2ffb 100644 --- a/doc/namespace.md +++ b/doc/namespace.md @@ -2,7 +2,7 @@ # Namespaces -A namespace is a type of value that groups together several values (fields) from the same scope. A block or file returns a namespace if it contains any export arrows `⇐` at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace can be mutable only if any of the code in it uses `↩` to change the value of a field. +A namespace is a type of value that groups together several variables (fields) from the same scope. A block or file returns a namespace if it contains any export arrows `⇐` at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace can be mutable only if any of its source code uses `↩` to change the value of a field. The following quick example shows a few ways to use a namespace returned by `•Import`: @@ -19,11 +19,11 @@ An here's how the contents of file.bqn might look in order to define the variabl ## Uses -The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that [closures](lexical.md#closures) provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't really expand the basic functionality of the language, but just make it easier to use. +The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that [closures](lexical.md#closures) provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't expand the basic functionality of the language, but just make it easier to use. Namespaces improve encapsulation by allowing many values to be exported at once. With only one way to call them, functions and modifiers aren't such a good way to define a large part of a program. With a namespace you can define lots of things and expose exactly the ones you want to the rest of the world. For example, it's typical for files to define namespaces. A reader can see the exported values just by searching for `⇐`, and if you're nice, you might declare them all at the beginning of the file. Careful use of exports can guarantee that potentially dangerous functions are used correctly: if it's only valid to call function `B` after function `A` has been called, export `AB⇐{A𝕩⋄B𝕩}` and don't export `B`. -Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain `↩`, as this is the only way it can modify the variables it contains. +Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain `↩`, as this is the only way it could modify the variables it contains. A namespace that makes use of mutability is essentially an object: a collection of state along with operations that act on it. [Object-oriented programming](oop.md) is the other major use of namespaces. Contrary to the name, there's never a need to orient your programming around objects, and it's perfectly fine to use an object here or there when you need to, for instance to build a mutable queue of values. @@ -40,22 +40,22 @@ The double arrow `⇐` is used to export variables from a block or file, making ## Imports -There are also two ways to get values out of a namespace, such as `example` defined above. First, it might be used in a [destructuring](expression.md#destructuring) assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like `b`, which gives both, or an aliasing expression like `b2⇐b`. In this case, the value `b` from the namespace is used, but it's given the name `b2` instead of `b`. Imported names can be repeated—but the variables defined can't—and all the names can be spelled with any role (the role is ignored). +There are also two ways to get values out of a namespace, such as `example` defined above. First, one field at a time can be retrieved with dot syntax: write the namespace, then a dot `.`, then another name. - ⟨alias⇐a, b, c0‿c1⇐c, b2⇐b⟩ ← example + example.b -If aliasing with `⇐` is never used (or each use is parenthesized), the names can be given as a strand with `‿`. + {n⇐7}.n - c‿a ← example +The part on the left can be anything with a subject role, although it will often need to be parenthesized because `.` has higher precedence than any operator. This allows it to be chained like `a.b.c` if a namespace has a value that is also a namespace (and so on). -The arrows `⇐` used for importing don't indicate that the surrounding block is a namespace or export variables. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is `⇐`. +Second, a namespace might be used in a [destructuring](expression.md#destructuring) assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like `b`, which gives both, or an aliasing expression like `b2⇐b`. In this case, the value `b` from the namespace is used, but it's given the name `b2` instead of `b`. Imported names can be repeated—but the variable names defined can't be—and all the names can be spelled with any role (the role is ignored). - ⟨two, vars⟩ ⇐ •Import "stuff.bqn" + ⟨alias⇐a, b, c0‿c1⇐c, b2⇐b⟩ ← example -The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot `.`, then another name. +If aliasing with `⇐` is never used (or each use is parenthesized), the names can be given as a strand with `‿`. - example.b + c‿a ← example - {n⇐7}.n +The arrow `⇐` used for an alias doesn't export anything or indicate that its block is a namespace. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is `⇐`. -The syntax is any subject followed by a dot and then a name. This can be chained like `a.b.c` if a namespace has a value that is also a namespace (and so on). + ⟨two, vars⟩ ⇐ •Import "stuff.bqn" diff --git a/doc/transpose.md b/doc/transpose.md index f1f978ad..e11ab359 100644 --- a/doc/transpose.md +++ b/doc/transpose.md @@ -18,7 +18,7 @@ Transpose is named this way because it exchanges the two axes of the matrix. Abo With two axes the only interesting operation of this sort is to swap them (and with one or zero axes there's nothing interesting to do, and `⍉` just returns the argument array). But a BQN programmer may well want to work with higher-rank arrays—although such a programmer might call them "tensors"—and this means there are many more ways to rearrange the axes. Transpose extends to high-rank arrays to allow some useful special cases as well as completely general axis rearrangement, as described below. -## Monadic Transpose +## Transposing tensors APL extends matrix transposition to any rank by reversing all axes for its monadic `⍉`, but this generalization isn't very natural and is almost never used. The main reason for it is to maintain the equivalence `a MP b ←→ b MP⌾⍉ a`, where `MP ← +˝∘×⎉1‿∞` is the generalized matrix product. But even here APL's Transpose is suspect. It does much more work than it needs to, as we'll see. diff --git a/docs/doc/glossary.html b/docs/doc/glossary.html index 85591356..16a1ade3 100644 --- a/docs/doc/glossary.html +++ b/docs/doc/glossary.html @@ -107,7 +107,7 @@ <li><strong>Access</strong>: To get the current value of a field from a namespace.</li> <li><a href="namespace.html#exports"><strong>Export</strong></a>: Declare a variable to be accessible from the outside, that is, make it a field.</li> <li><a href="oop.html"><strong>Object</strong></a>: Informal term for a namespace that holds mutable state.</li> -<li><strong>Alias</strong>: A different "outside" name chosen for a field in a destructuring assignment.</li> +<li><a href="namespace.html#imports"><strong>Alias</strong></a>: A different "outside" name chosen for a field in a destructuring assignment.</li> </ul> <h2 id="tokens"><a class="header" href="#tokens">Tokens</a></h2> <ul> diff --git a/docs/doc/lexical.html b/docs/doc/lexical.html index dcc5fef0..290a2a37 100644 --- a/docs/doc/lexical.html +++ b/docs/doc/lexical.html @@ -6,7 +6,7 @@ <div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div> <h1 id="lexical-scoping"><a class="header" href="#lexical-scoping">Lexical scoping</a></h1> <p>BQN uses lexical scope, like most modern functional programming languages including Javascript, Scheme, and Julia, and like Dyalog APL's dfns (tradfns are dynamically scoped). This document describes how lexical scoping works, and a few small details relevant to BQN's version of it.</p> -<p>In short, every <a href="block.html">block</a> is a separate scope that can refer to identifiers in containing scopes. When evaluated, the block makes a variable for each identifier defined in it (including arguments and operands). The blocks that it contains will now access these variables. In the first level of a block, variables must be defined before they can be used, but in child blocks, a variable can be used regardless of where it's defined, as long as the definition is evaluated before the child block is.</p> +<p>In short, every <a href="block.html">block</a> is a separate scope, but can use identifiers in containing scopes. Each time it's evaluated, the block makes a variable for each identifier defined in it (including arguments and operands). The blocks that it contains might access these variables. At the top level of a block, identifiers must be defined before they can be used, but in child blocks, an identifier can be used even if it's defined later, as long as that use isn't evaluated before the definition can set the variable value.</p> <h2 id="scopes"><a class="header" href="#scopes">Scopes</a></h2> <p>Scoping is a mechanism that allows the same variable name to refer to different variables depending on program context. For example, the following code uses the name <code><span class='Value'>a</span></code> in two ways: once for a value at the top level, and once locally in a function. With scoping, once you write <code><span class='Brace'>{}</span></code> to create a block, you can define any name you want inside without worrying whether it's taken.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=YSDihpAgNgpGIOKGkCB7IGEgw5cgMSArIGEg4oaQIPCdlakgfQoKRiA0ICAgICMgU2V0cyBh4oaQNCBpbnRlcm5hbGx5CmEgICAgICAjIFRoZSBvdXRlciBhIGlzIHVuY2hhbmdlZA==">↗️</a><pre> <span class='Value'>a</span> <span class='Gets'>←</span> <span class='Number'>6</span> @@ -18,7 +18,7 @@ </span>6 </pre> <p>Above, the scope of the first <code><span class='Value'>a</span></code> is the entire program, while the scope of the second <code><span class='Value'>a</span></code> is limited to the body of <code><span class='Function'>F</span></code>. So one form of context is that a name might mean different things depending on which block contains it. But even the exact same instance of a name in the source code might mean multiple things! A second kind of context is which evaluation of a block uses the name.</p> -<p>Without this ability BQN would be pretty limited: for example, an <a href="oop.html">object</a>'s fields are variables. If the variable value didn't depend on what object contained it, there could effectively only be one instance of each object! While it's needed all the time, the most direct way to demonstrate one name meaning multiple things is with recursion. The (fragile) function below labels each element in a nested list structure with its index in the list containing it.</p> +<p>Without this ability BQN would be pretty limited: for example, an <a href="oop.html">object</a>'s fields are variables. If the variable value didn't depend on what object contained it, there could effectively only be one instance of each object! It's not the most common use case, but recursion is the most direct way to demonstrate a name meaning multiple things at once. The (fragile) function below labels each element in a nested list structure with its index in the list containing it.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=TGFiZWwg4oaQIHsgaeKGkOKGleKJoPCdlakg4ouEIGkg4omNIPCdlYrijZ89wqgg8J2VqSB9CgpMYWJlbCDin6giYWIi4oC/OCwgN+KAvzbigL814p+p">↗️</a><pre> <span class='Function'>Label</span> <span class='Gets'>←</span> <span class='Brace'>{</span> <span class='Value'>i</span><span class='Gets'>←</span><span class='Function'>↕≠</span><span class='Value'>𝕩</span> <span class='Separator'>⋄</span> <span class='Value'>i</span> <span class='Function'>≍</span> <span class='Function'>𝕊</span><span class='Modifier2'>⍟</span><span class='Function'>=</span><span class='Modifier'>¨</span> <span class='Value'>𝕩</span> <span class='Brace'>}</span> <span class='Function'>Label</span> <span class='Bracket'>⟨</span><span class='String'>"ab"</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Separator'>,</span> <span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Bracket'>⟩</span> @@ -36,7 +36,7 @@ <p>Each call creates the <a href="range.html">list of indices</a> <code><span class='Value'>i</span></code>, then calls itself using <code><span class='Function'>𝕊</span></code> on each element of <code><span class='Value'>𝕩</span></code> <a href="repeat.html">if</a> it's a list, then <a href="couple.html">couples</a> <code><span class='Value'>i</span></code> to the result. This requires <code><span class='Value'>i</span></code> to be unaffected by other calls to the function, which works because <code><span class='Value'>i</span></code> is scoped not only to the source code location but also to the particular evaluation of the block that creates it.</p> <p>These examples probably work like you expect—they're meant to highlight the features that scoping should have, in order to help show how less intuitive cases work later on.</p> <h2 id="visibility"><a class="header" href="#visibility">Visibility</a></h2> -<p>A scope can view and modify (with <code><span class='Gets'>↩</span></code>) variables in other scopes that contain it. We say these variables are visible in the inner scopes. Variables at the top level of a program are visible to all the code in that program, so that we might call them "global". That would be a little misleading though, because for example each file is an entire program, so if one file is imported from another then it can't read the first file's variables.</p> +<p>A scope can view and <a href="expression.html#assignment">modify</a> (with <code><span class='Gets'>↩</span></code>) variables in other scopes that contain it. We say these variables are <em>visible</em> in the inner scopes. Variables at the top level of a program are visible to all the code in that program, so that we might call them "global". That's somewhat misleading, because for example each file is an entire program, so if one file is imported from another then it can't read the first file's variables.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=Y291bnRlciDihpAgMAppbmMg4oaQIDYKQ291bnQg4oaQIHsgY291bnRlciAr4oapIPCdlakgw5cgaW5jIH0KCkNvdW50IDAKQ291bnQgMQpDb3VudCAxCkNvdW50IDU=">↗️</a><pre> <span class='Value'>counter</span> <span class='Gets'>←</span> <span class='Number'>0</span> <span class='Value'>inc</span> <span class='Gets'>←</span> <span class='Number'>6</span> <span class='Function'>Count</span> <span class='Gets'>←</span> <span class='Brace'>{</span> <span class='Value'>counter</span> <span class='Function'>+</span><span class='Gets'>↩</span> <span class='Value'>𝕩</span> <span class='Function'>×</span> <span class='Value'>inc</span> <span class='Brace'>}</span> @@ -108,7 +108,7 @@ </pre> <p>Each result keeps its own counter and the different copies don't interfere with each other. This is because every call to <code><span class='Modifier'>_makeCount</span></code> is isolated, happening in its own world. We say that whenever a block begins execution it creates an <em>environment</em> where all its variables are stored. This environment might even be exposed later on, as a <a href="namespace.html">namespace</a>.</p> <p>Each counter function has access to the environment containing its <code><span class='Value'>counter</span></code> and <code><span class='Value'>inc</span></code>, even though the block that created that environment (<code><span class='Modifier'>_makeCount</span></code>) has finished execution—it must have finished, since we are now using the function it returns on the last line. There's nothing particularly weird about this; just because a block creates an environment when it starts doesn't mean it has to destroy it when it finishes. From the mathematical perspective, it's easiest to say the environment exists forever, but a practical implementation will perform garbage collection to free environments that are no longer reachable.</p> -<p>Since a function like <code><span class='Function'>C1_4</span></code> maintains access to all the variables it needs to run, we say it <em>encloses</em> those variables, and call it a <em>closure</em>. It doesn't need to modify them. For example, even the following definition of <code><span class='Value'>stdDev</span></code> is a closure.</p> +<p>Since a function like <code><span class='Function'>C1_4</span></code> maintains access to all the variables it needs to run, we say it <em>encloses</em> those variables, and call it a <em>closure</em>. It doesn't need to modify them. For example, the following definition of the theoretical standard deviation function <code><span class='Function'>StdDev</span></code> is also a closure.</p> <pre><span class='Value'>stdDev</span> <span class='Gets'>←</span> <span class='Brace'>{</span> <span class='Comment'># Arithmetic mean </span> <span class='Function'>Mean</span> <span class='Gets'>←</span> <span class='Function'>+</span><span class='Modifier'>´</span> <span class='Function'>÷</span> <span class='Function'>≠</span> @@ -127,7 +127,7 @@ <p>We've seen that one block can create many environments. An environment can have only one parent, but many children, so environments form a tree. A forest to be precise, as one execution of BQN can involve multiple programs.</p> <p>How does an environment know which of the many environments corresponding to the parent scope is its parent? This information is saved when the block is reached in the program and a <em>block instance</em> is created. Unless it's an immediate block, the block instance won't be run right away: a block instance isn't the same as a block evaluation. But each block evaluation starts with a block instance, and that's where it gets the parent environment. Unlike block evaluation, which can happen anywhere, a block instance is created only during evaluation of the parent block. So the saved parent environment is simply the current environment.</p> <h2 id="mutation"><a class="header" href="#mutation">Mutation</a></h2> -<p>The value of a variable can be modified with <code><span class='Gets'>↩</span></code>. It's similar to definition <code><span class='Gets'>←</span></code> in that it sets the value of the variable, but the way it interacts with scoping is completely different. Defining creates a new variable in the current scope, and modifying refers to an existing variable in the current scope or a parent. In scoping terms, modifying is more like an ordinary variable reference than a definition.</p> +<p>The value of a variable can be modified with <code><span class='Gets'>↩</span></code>. It's similar to definition <code><span class='Gets'>←</span></code> in that it sets the value of the variable, but the way it interacts with scoping is completely different. Definition creates a new variable in the current scope, and modification refers to an existing variable in the current scope or a parent. In scoping terms, a modification is more like an ordinary variable reference than a definition.</p> <p>When a variable's modified, functions with access to it see the new value. They have access to the variable, not any particular value that it has.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ZmFjdG9yIOKGkCAzCk11bCDihpAgeyBmYWN0b3Igw5cg8J2VqSB9CgpNdWwgNgpmYWN0b3Ig4oapIDUKTXVsIDYgICAjIEEgbmV3IHJlc3VsdA==">↗️</a><pre> <span class='Value'>factor</span> <span class='Gets'>←</span> <span class='Number'>3</span> <span class='Function'>Mul</span> <span class='Gets'>←</span> <span class='Brace'>{</span> <span class='Value'>factor</span> <span class='Function'>×</span> <span class='Value'>𝕩</span> <span class='Brace'>}</span> @@ -138,7 +138,7 @@ <span class='Function'>Mul</span> <span class='Number'>6</span> <span class='Comment'># A new result </span>30 </pre> -<p>Only 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 a constant in each environment that contains it (not necessarily across environments). That is, constant once it's defined: it's still possible to get an error if the variable is accessed before being defined.</p> +<p>Only 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 a constant in each environment that contains it (not necessarily across environments). 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.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=eyB7IGEgfSDii4QgYeKGkDQgfQ==">↗️</a><pre> <span class='Brace'>{</span> <span class='Brace'>{</span> <span class='Value'>a</span> <span class='Brace'>}</span> <span class='Separator'>⋄</span> <span class='Value'>a</span><span class='Gets'>←</span><span class='Number'>4</span> <span class='Brace'>}</span> <span class='Error'>Error: Reading variable before its defined</span> </pre> diff --git a/docs/doc/logic.html b/docs/doc/logic.html index 19d4f294..18cf1add 100644 --- a/docs/doc/logic.html +++ b/docs/doc/logic.html @@ -5,19 +5,9 @@ </head> <div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div> <h1 id="logic-functions-and-or-not-also-span"><a class="header" href="#logic-functions-and-or-not-also-span">Logic functions: And, Or, Not (also Span)</a></h1> -<p>BQN uses the mathematical symbols <code><span class='Function'>∧</span></code> and <code><span class='Function'>∨</span></code> for logical <em>and</em> and <em>or</em>, and <code><span class='Function'>¬</span></code> for <em>not</em> (APL's <code><span class='Value'>~</span></code> is discarded since it looks like <code><span class='Modifier'>˜</span></code>, and is less common in mathematics today). These functions are arithmetically extended to apply to all numbers. In the case of Not, that means the linear function <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>-</span></code>. The two-argument functions have bilinear extensions: And is identical to Times (<code><span class='Function'>×</span></code>), while Or is <code><span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span></code>, following De Morgan's laws (other ways of obtaining a function for Or give an equivalent result—there is only one bilinear extension).</p> -<p>If the arguments are probabilities of independent events, then an extended function gives the probability of the boolean function on their outcomes (for example, if <em>A</em> occurs with probability <code><span class='Value'>a</span></code> and <em>B</em> with probability <code><span class='Value'>b</span></code> independent of <em>A</em>, then <em>A</em> or <em>B</em> occurs with probability <code><span class='Value'>a</span><span class='Function'>∨</span><span class='Value'>b</span></code>). These extensions have also been used in complexity theory, because they allow mathematicians to transfer a logical circuit from the discrete to the continuous domain in order to use calculus on it.</p> +<p>BQN uses the mathematical symbols <code><span class='Function'>∧</span></code> and <code><span class='Function'>∨</span></code> for logical <em>and</em> and <em>or</em>, and <code><span class='Function'>¬</span></code> for <em>not</em> (APL's <code><span class='Value'>~</span></code> is discarded since it looks like <code><span class='Modifier'>˜</span></code>, and is less common in mathematics today). That is, on two booleans <code><span class='Function'>∧</span></code> is 1 if both are 1, and <code><span class='Function'>∨</span></code> is if either is 1. <code><span class='Function'>¬</span></code> flips its argument, returning 1 if the argument is 0 and 0 if it's 1. The logic functions are also considered <a href="arithmetic.html">arithmetic</a> and thus are <a href="arithmetic.html#pervasion">pervasive</a>.</p> +<p>These boolean functions are arithmetically extended to apply to all numbers. Not returns <code><span class='Number'>1</span><span class='Function'>-</span><span class='Value'>𝕩</span></code>, And returns <code><span class='Value'>𝕨</span><span class='Function'>×</span><span class='Value'>𝕩</span></code>, and Or does a more complicated computation <code><span class='Value'>𝕨</span><span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span><span class='Value'>𝕩</span></code>.</p> <p>Both valences of <code><span class='Function'>¬</span></code> are equivalent to the fork <code><span class='Number'>1</span><span class='Function'>+-</span></code>. The dyadic valence, called "Span", computes the number of integers in the range from <code><span class='Value'>𝕩</span></code> to <code><span class='Value'>𝕨</span></code>, inclusive, when both arguments are integers and <code><span class='Value'>𝕩</span><span class='Function'>≤</span><span class='Value'>𝕨</span></code> (note the reversed order, which is used for consistency with subtraction). This function has many uses, and in particular is relevant to the <a href="windows.html">Windows</a> function.</p> -<p>These functions are considered <a href="arithmetic.html">arithmetic</a> functions and thus are <a href="arithmetic.html#pervasion">pervasive</a>.</p> -<h2 id="definitions"><a class="header" href="#definitions">Definitions</a></h2> -<p>We define:</p> -<pre><span class='Function'>Not</span> <span class='Gets'>←</span> <span class='Number'>1</span><span class='Function'>+-</span> <span class='Comment'># also Span -</span><span class='Function'>And</span> <span class='Gets'>←</span> <span class='Function'>×</span> -<span class='Function'>Or</span> <span class='Gets'>←</span> <span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span> -</pre> -<p>Note that <code><span class='Function'>¬</span><span class='Modifier'>⁼</span> <span class='Gets'>←→</span> <span class='Function'>¬</span></code>, since when applying <code><span class='Function'>¬</span></code> twice the first added 1 will be negated but the second won't; the two 1s cancel leaving two subtractions, and <code><span class='Function'>-</span><span class='Modifier'>⁼</span> <span class='Gets'>←→</span> <span class='Function'>-</span></code>. An alternate definition of Or that matches the typical formula from probability theory is</p> -<pre><span class='Function'>Or</span> <span class='Gets'>←</span> <span class='Function'>+-×</span> -</pre> <h2 id="examples"><a class="header" href="#examples">Examples</a></h2> <p>We can form truth <a href="map.html#table">tables</a> including the non-integer value one-half:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=wqwgMOKAvzAuNeKAvzEKCuKIp+KMnMucIDDigL8wLjXigL8xCgriiKjijJzLnCAw4oC/MC414oC/MQ==">↗️</a><pre> <span class='Function'>¬</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0.5</span><span class='Ligature'>‿</span><span class='Number'>1</span> @@ -38,10 +28,21 @@ ┘ </pre> <p>As with logical And and Or, any value and 0 is 0, while any value or 1 is 1. The other boolean values give the identity values for the two functions: 1 and any value gives that value, as does 0 or the value.</p> -<h2 id="why-not-gcd-and-lcm"><a class="header" href="#why-not-gcd-and-lcm">Why not GCD and LCM?</a></h2> -<p>APL provides <a href="https://aplwiki.com/wiki/GCD">GCD</a> and <a href="https://aplwiki.com/wiki/LCM">LCM</a> as extensions of And and Or, while BQN doesn't make these functions primitives. The main reason for omitting them functions is that they are complicated and, when applied to real or complex numbers, require a significant number of design decisions where there is no obvious choice (for example, whether to use comparison tolerance). On the other hand, these functions are fairly easy to implement, which allows the programmer to control the details, and also add functionality such as the extended GCD. Possible implementations for GCD and LCM are shown in <a href="https://mlochbaum.github.io/bqncrate">bqncrate</a> (<a href="https://mlochbaum.github.io/bqncrate/?q=gcd">GCD</a>, <a href="https://mlochbaum.github.io/bqncrate/?q=lcm">LCM</a>).</p> -<p>A secondary reason is that the GCD falls short as an extension of Or, because its identity value 0 is not total. <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Value'>x</span></code>, for a real number <code><span class='Value'>x</span></code>, is actually equal to <code><span class='Function'>|</span><span class='Value'>x</span></code> and not <code><span class='Value'>x</span></code>: for example, <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Number'>¯2</span></code> is <code><span class='Number'>2</span></code> in APL. This means the identity <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Value'>x</span> <span class='Gets'>←→</span> <span class='Value'>x</span></code> isn't reliable in APL.</p> +<h2 id="definitions"><a class="header" href="#definitions">Definitions</a></h2> +<p>We define</p> +<pre><span class='Function'>Not</span> <span class='Gets'>←</span> <span class='Number'>1</span><span class='Function'>+-</span> <span class='Comment'># also Span +</span><span class='Function'>And</span> <span class='Gets'>←</span> <span class='Function'>×</span> +<span class='Function'>Or</span> <span class='Gets'>←</span> <span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span> +</pre> +<p>using a <a href="train.html">train</a> for Not and <a href="under.html">Under</a> for Or. The latter expands to <code><span class='Function'>Or</span> <span class='Gets'>←</span> <span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>×</span><span class='Modifier2'>○</span><span class='Function'>¬</span></code>, since Not is a self-inverse <code><span class='Function'>¬</span><span class='Modifier'>⁼</span> <span class='Gets'>←→</span> <span class='Function'>¬</span></code>: when applying <code><span class='Function'>¬</span></code> twice the first added 1 will be negated but the second won't; the two 1s cancel leaving two subtractions, and <code><span class='Function'>-</span><span class='Modifier'>⁼</span> <span class='Gets'>←→</span> <span class='Function'>-</span></code>. An alternate definition of Or that matches the typical formula from probability theory is</p> +<pre><span class='Function'>Or</span> <span class='Gets'>←</span> <span class='Function'>+-×</span> +</pre> +<p>The logic functions are extended to all numbers by making them linear in every argument. In the case of Not, that means the linear function <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>-</span></code>. The two-argument functions have bilinear extensions: And is identical to Times (<code><span class='Function'>×</span></code>), while Or is <code><span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span></code>, following De Morgan's laws (other ways of obtaining a function for Or give an equivalent result—there is only one bilinear extension).</p> +<p>If the arguments are probabilities of independent events, then an extended function gives the probability of the boolean function on their outcomes. For example, if <em>A</em> occurs with probability <code><span class='Value'>a</span></code> and <em>B</em> with probability <code><span class='Value'>b</span></code> independent of <em>A</em>, then at least one of <em>A</em> or <em>B</em> occurs with probability <code><span class='Value'>a</span><span class='Function'>∨</span><span class='Value'>b</span></code>. These extensions have also been used in complexity theory, because they allow mathematicians to transfer a logical circuit from the discrete to the continuous domain in order to use calculus on it.</p> <h2 id="identity-values"><a class="header" href="#identity-values">Identity values</a></h2> <p>It's common to apply a <a href="fold.html">fold</a> <code><span class='Function'>∧</span><span class='Modifier'>´</span></code> or <code><span class='Function'>∨</span><span class='Modifier'>´</span></code> to a list (checking whether all elements are true and whether any are true, respectively), and so it's important for extensions to And and Or to share their <a href="fold.html#identity-values">identity</a> value. <a href="arithmetic.html#additional-arithmetic">Minimum and Maximum</a> do match And and Or when restricted to booleans, but they have different identity values. It would be dangerous to use Maximum to check whether any element of a list is true because <code><span class='Function'>⌈</span><span class='Modifier'>´</span><span class='Bracket'>⟨⟩</span></code> yields <code><span class='Number'>¯∞</span></code> instead of <code><span class='Number'>0</span></code>—a bug waiting to happen. To avoid this the programmer would have to use an initial value <code><span class='Value'>𝕨</span></code> of <code><span class='Number'>0</span></code>, which is easy to forget.</p> <p>It's not hard to prove that the bilinear extensions have the identity values we want. Of course <code><span class='Number'>1</span><span class='Function'>∧</span><span class='Value'>x</span></code> is <code><span class='Number'>1</span><span class='Function'>×</span><span class='Value'>x</span></code>, or <code><span class='Value'>x</span></code>, and <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Value'>x</span></code> is <code><span class='Number'>0</span><span class='Function'>×</span><span class='Modifier2'>⌾</span><span class='Function'>¬</span><span class='Value'>x</span></code>, or <code><span class='Function'>¬</span><span class='Number'>1</span><span class='Function'>׬</span><span class='Value'>x</span></code>, giving <code><span class='Function'>¬¬</span><span class='Value'>x</span></code> or <code><span class='Value'>x</span></code> again. Both functions are commutative, so these values are identities on the right as well.</p> <p>Other logical identities do not necessarily hold. For example, in boolean logic And distributes over Or and vice-versa: <code><span class='Value'>a</span><span class='Function'>∧</span><span class='Value'>b</span><span class='Function'>∨</span><span class='Value'>c</span> <span class='Gets'>←→</span> <span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>∧</span><span class='Value'>b</span><span class='Paren'>)</span><span class='Function'>∨</span><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>∧</span><span class='Value'>c</span><span class='Paren'>)</span></code>. But substituting <code><span class='Function'>×</span></code> for <code><span class='Function'>∧</span></code> and <code><span class='Function'>+-×</span></code> for <code><span class='Function'>∨</span></code> we find that the left hand side is <code><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>b</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>c</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>b</span><span class='Function'>×</span><span class='Value'>c</span><span class='Paren'>)</span></code> while the right gives <code><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>b</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>c</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>b</span><span class='Function'>×</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>c</span><span class='Paren'>)</span></code>. These are equivalent for arbitrary <code><span class='Value'>b</span></code> and <code><span class='Value'>c</span></code> only if <code><span class='Value'>a</span><span class='Function'>=</span><span class='Value'>a</span><span class='Function'>×</span><span class='Value'>a</span></code>, that is, <code><span class='Value'>a</span></code> is 0 or 1. In terms of probabilities the difference when <code><span class='Value'>a</span></code> is not boolean is caused by failure of independence. On the left hand side, the two arguments of every logical function are independent. On the right hand side, each pair of arguments to <code><span class='Function'>∧</span></code> are independent, but the two arguments to <code><span class='Function'>∨</span></code>, <code><span class='Value'>a</span><span class='Function'>∧</span><span class='Value'>b</span></code> and <code><span class='Value'>a</span><span class='Function'>∧</span><span class='Value'>c</span></code>, are not. The relationship between these arguments means that logical equivalences no longer apply.</p> +<h2 id="why-not-gcd-and-lcm"><a class="header" href="#why-not-gcd-and-lcm">Why not GCD and LCM?</a></h2> +<p>APL provides <a href="https://aplwiki.com/wiki/GCD">GCD</a> and <a href="https://aplwiki.com/wiki/LCM">LCM</a> as extensions of And and Or, while BQN doesn't make these functions primitives. The main reason for omitting them functions is that they are complicated and, when applied to real or complex numbers, require a significant number of design decisions where there's no obvious choice (for example, whether to use comparison tolerance). On the other hand, these functions are fairly easy to implement, which allows the programmer to control the details, and also add functionality such as the extended GCD. Possible implementations for GCD and LCM are shown in <a href="https://mlochbaum.github.io/bqncrate">bqncrate</a> (<a href="https://mlochbaum.github.io/bqncrate/?q=gcd">GCD</a>, <a href="https://mlochbaum.github.io/bqncrate/?q=lcm">LCM</a>).</p> +<p>A secondary reason is that the GCD falls short as an extension of Or, because its identity value 0 is not total. <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Value'>x</span></code>, for a real number <code><span class='Value'>x</span></code>, is actually equal to <code><span class='Function'>|</span><span class='Value'>x</span></code> and not <code><span class='Value'>x</span></code>: for example, <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Number'>¯2</span></code> is <code><span class='Number'>2</span></code> in APL. This means the identity <code><span class='Number'>0</span><span class='Function'>∨</span><span class='Value'>x</span> <span class='Gets'>←→</span> <span class='Value'>x</span></code> isn't reliable in APL.</p> diff --git a/docs/doc/map.html b/docs/doc/map.html index f84421cf..396b0a48 100644 --- a/docs/doc/map.html +++ b/docs/doc/map.html @@ -6,7 +6,7 @@ <div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div> <h1 id="mapping-modifiers"><a class="header" href="#mapping-modifiers">Mapping modifiers</a></h1> <p>Mapping a function over an array means to call it on each element of that array, creating an array of results. It's also possible to map over two arrays, applying the function to various choices of one element from each, but there's no longer a single correct way to iterate over these elements.</p> -<p>BQN has two 1-modifiers to map over arrays: Each (<code><span class='Modifier'>¨</span></code>) and Table (<code><span class='Modifier'>⌜</span></code>). On two arguments, Table applies its operand to all combinations of elements while Each creates a one-to-one or one-to-many matching. Since they apply to elements, these modifiers are different from Cells (<code><span class='Modifier'>˘</span></code>) or its generalization Rank (<code><span class='Modifier2'>⎉</span></code>), which apply the function to array cells. The modifier <a href="depth.html#the-depth-modifier">Depth</a> (<code><span class='Modifier2'>⚇</span></code>) is a generalization of Each, so that <code><span class='Modifier'>¨</span></code> is <code><span class='Modifier2'>⚇</span><span class='Number'>¯1</span></code>; however, it can't be used to implement Table without some additional array operations.</p> +<p>As a result, BQN has two 1-modifiers to map over arrays: Each (<code><span class='Modifier'>¨</span></code>) and Table (<code><span class='Modifier'>⌜</span></code>). On two arguments, Table applies its operand to all combinations of elements while Each creates a one-to-one or one-to-many matching. Since they apply to elements, these modifiers are different from <a href="rank.html#cells">Cells</a> (<code><span class='Modifier'>˘</span></code>) or its generalization <a href="rank.html#rank">Rank</a> (<code><span class='Modifier2'>⎉</span></code>), which apply the function to array cells. The modifier <a href="depth.html#the-depth-modifier">Depth</a> (<code><span class='Modifier2'>⚇</span></code>) is a generalization of Each, so that <code><span class='Modifier'>¨</span></code> is <code><span class='Modifier2'>⚇</span><span class='Number'>¯1</span></code>; however, it can't be used to implement Table without some additional array operations.</p> <h2 id="one-argument-mapping"><a class="header" href="#one-argument-mapping">One-argument mapping</a></h2> <svg viewBox='-224 -21.6 680 187.2'> <g fill='currentColor' font-family='BQN,monospace'> @@ -133,7 +133,7 @@ "C0" "C1" "C2" "C3" "C4" ┘ </pre> -<p>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 (<code><span class='Modifier'>˜</span></code>):</p> +<p>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 <a href="swap.html">Self</a> (<code><span class='Modifier'>˜</span></code>):</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=w5fijJzLnCAxK+KGlTY=">↗️</a><pre> <span class='Function'>×</span><span class='Modifier'>⌜˜</span> <span class='Number'>1</span><span class='Function'>+↕</span><span class='Number'>6</span> ┌─ ╵ 1 2 3 4 5 6 @@ -213,11 +213,11 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=IkFCQ0QiIOKJjcKoICIwMTIzIg==">↗️</a><pre> <span class='String'>"ABCD"</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='String'>"0123"</span> ⟨ "A0" "B1" "C2" "D3" ⟩ </pre> -<p>This makes for a lot fewer applications than Table. Only the diagonal elements from Table's result are seen, as we can check with <a href="transpose.html">Transpose</a>.</p> +<p>This makes for a lot fewer applications than Table. Only the diagonal elements from Table's result are seen, as we can check with <a href="transpose.html#reorder-axes">Reorder Axes</a>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MOKAvzAg4o2JICJBQkNEIiDiiY3ijJwgIjAxMjMi">↗️</a><pre> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Function'>⍉</span> <span class='String'>"ABCD"</span> <span class='Function'>≍</span><span class='Modifier'>⌜</span> <span class='String'>"0123"</span> ⟨ "A0" "B1" "C2" "D3" ⟩ </pre> -<p>If the argument lengths don't match then Each gives an error. This contrasts with 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.</p> +<p>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.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=IkFCQyIg4omNwqggIjAxMjM0Ig==">↗️</a><pre> <span class='String'>"ABC"</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='String'>"01234"</span> <span class='Error'>Error: Mapping: Expected equal shape prefix (⟨3⟩ ≡ ≢𝕨, ⟨5⟩ ≡ ≢𝕩)</span> </pre> @@ -228,12 +228,13 @@ ⟨ 50 51 52 ⟩ ⟨ 40 41 ⟩ ⟨ 60 ⟩ ┘ </pre> -<p>But arguments don't have to have exactly the same shape: just the same length along corresponding axes. These axes are matched up according to the <a href="leading.html">leading axis convention</a>, 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.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiICgw4oC/MuKAvzbipYpAKSDiiY3CqCAw4oC/MeKlijAgICMgVG9vIHNtYWxsCuKJoiAoMOKAvzLigL824qWKQCkg4omNwqggMOKAvzLipYowICAjIEp1c3QgcmlnaHQK4omiICgw4oC/MuKAvzbipYpAKSDiiY3CqCAw4oC/M+KlijAgICMgVG9vIGxhcmdl">↗️</a><pre> <span class='Function'>≢</span> <span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>⥊</span><span class='String'>@</span><span class='Paren'>)</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Function'>⥊</span><span class='Number'>0</span> <span class='Comment'># Too small +<p>But arguments don't have to have exactly the same shape: just the same length along corresponding axes. These axes are matched up by <a href="leading.html#leading-axis-agreement">leading axis agreement</a>, 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.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiICgw4oC/MuKAvzbipYpAKSDiiY3CqCAw4oC/MeKlijAgICMgVG9vIHNtYWxsCgriiaIgKDDigL8y4oC/NuKlikApIOKJjcKoIDDigL8z4qWKMCAgIyBUb28gbGFyZ2UKCuKJoiAoMOKAvzLigL824qWKQCkg4omNwqggMOKAvzLipYowICAjIEp1c3QgcmlnaHQ=">↗️</a><pre> <span class='Function'>≢</span> <span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>⥊</span><span class='String'>@</span><span class='Paren'>)</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Function'>⥊</span><span class='Number'>0</span> <span class='Comment'># Too small </span><span class='Error'>Error: Mapping: Expected equal shape prefix (0‿2‿6 ≡ ≢𝕨, 0‿1 ≡ ≢𝕩)</span> - <span class='Function'>≢</span> <span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>⥊</span><span class='String'>@</span><span class='Paren'>)</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊</span><span class='Number'>0</span> <span class='Comment'># Just right -</span>⟨ 0 2 6 ⟩ + <span class='Function'>≢</span> <span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>⥊</span><span class='String'>@</span><span class='Paren'>)</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Function'>⥊</span><span class='Number'>0</span> <span class='Comment'># Too large </span><span class='Error'>Error: Mapping: Expected equal shape prefix (0‿2‿6 ≡ ≢𝕨, 0‿3 ≡ ≢𝕩)</span> + + <span class='Function'>≢</span> <span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>⥊</span><span class='String'>@</span><span class='Paren'>)</span> <span class='Function'>≍</span><span class='Modifier'>¨</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊</span><span class='Number'>0</span> <span class='Comment'># Just right +</span>⟨ 0 2 6 ⟩ </pre> -<p>Leading axis agreement is described further <a href="leading.html#leading-axis-agreement">here</a>.</p> diff --git a/docs/doc/match.html b/docs/doc/match.html index 95336280..767a4bb5 100644 --- a/docs/doc/match.html +++ b/docs/doc/match.html @@ -23,9 +23,9 @@ 0 </pre> <p>Match compares arrays based on their fundamental properties—<a href="shape.html">shape</a> and elements—and not the <a href="fill.html">fill element</a>, which is an inferred property. Since it can be computed differently in different implementations, using the fill element in Match could lead to some confusing results. Even if the implementation doesn't define a fill for <code><span class='String'>'a'</span><span class='Ligature'>‿</span><span class='String'>'b'</span><span class='Ligature'>‿</span><span class='String'>'c'</span></code>, it should still be considered to match <code><span class='String'>"abc"</span></code>.</p> -<p>To give a precise definition, two arrays are considered to match if they have the same shape and all corresponding elements from the two arrays match. Every array has a finite <a href="depth.html">depth</a> so this recursive definition always ends up comparing non-arrays, or atoms. An array never matches an atom, so the result if only one argument is an atom is <code><span class='Number'>0</span></code>. The interesting case is when both arguments are atoms, discussed below.</p> +<p>To give a precise definition, two arrays are considered to match if they have the same shape and all corresponding elements from the two arrays match. Every array has a finite <a href="depth.html">depth</a>, so this recursive definition always ends up comparing non-arrays, or atoms. And because an array never matches an atom, the result if only one argument is an atom is <code><span class='Number'>0</span></code>. The interesting case is when both arguments are atoms, discussed below.</p> <h2 id="atomic-equality"><a class="header" href="#atomic-equality">Atomic equality</a></h2> -<p>Atoms in BQN have six possible <a href="types.html">types</a>: number, character, function, 1-modifier, 2-modifier, and namespace. Equality is not allowed to fail for any two arguments, so it needs to be defined on all of these types.</p> +<p>Atoms in BQN have six possible <a href="types.html">types</a>: number, character, function, 1-modifier, 2-modifier, and namespace. Equality testing isn't allowed to fail for any two arguments, so it needs to be defined on all of these types.</p> <p>Starting with the easiest rules, values with different types are never equal to each other.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4p+oJ2EnLCArLCAz4p+pID0g4p+oLeKfnMK7LCAnKycsIDPLmeKfqQ==">↗️</a><pre> <span class='Bracket'>⟨</span><span class='String'>'a'</span><span class='Separator'>,</span> <span class='Function'>+</span><span class='Separator'>,</span> <span class='Number'>3</span><span class='Bracket'>⟩</span> <span class='Function'>=</span> <span class='Bracket'>⟨</span><span class='Function'>-</span><span class='Modifier2'>⟜</span><span class='Function'>»</span><span class='Separator'>,</span> <span class='String'>'+'</span><span class='Separator'>,</span> <span class='Number'>3</span><span class='Modifier'>˙</span><span class='Bracket'>⟩</span> ⟨ 0 0 0 ⟩ @@ -37,13 +37,13 @@ <span class='Number'>1.25</span> <span class='Function'>=</span> <span class='Number'>1</span> <span class='Function'>+</span> <span class='Number'>0.25</span> 1 </pre> -<p>Mutable types are more difficult. Here there are three cases:</p> +<p>Operations and namespaces are more difficult. Here there are three cases:</p> <ul> <li>Primitives are equal if they have the same glyph.</li> <li>Compound functions or modifiers are split into components.</li> <li>Block instances or namespaces are equal if they are the same instance.</li> </ul> -<p>The first two are fairly similar to how numbers and arrays work. Primitives and compounds like trains, or modifiers with bound operands, are immutable, so they are defined purely by what components they contain.</p> +<p>The first two are fairly similar to how numbers and arrays work. Primitives and compounds like trains, or modifiers with bound operands, are immutable, so they're defined purely by what components they contain.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4p+oKywtLMOX4p+pID0g4p+oKywtLMO34p+pCgrin6grIC0gw5fin6kgPSDin6grIC0gw7fin6kgICMgQ29tcGFyZSB0d28gdGhyZWUtdHJhaW5zIGNvbXBvbmVudC13aXNlCgrin6grIC0gw7fin6kgPSDin6grIC0gw7fin6k=">↗️</a><pre> <span class='Bracket'>⟨</span><span class='Function'>+</span><span class='Separator'>,</span><span class='Function'>-</span><span class='Separator'>,</span><span class='Function'>×</span><span class='Bracket'>⟩</span> <span class='Function'>=</span> <span class='Bracket'>⟨</span><span class='Function'>+</span><span class='Separator'>,</span><span class='Function'>-</span><span class='Separator'>,</span><span class='Function'>÷</span><span class='Bracket'>⟩</span> ⟨ 1 1 0 ⟩ @@ -66,7 +66,7 @@ <span class='Function'>F</span> <span class='Number'>5</span> <span class='Comment'># Another result—the definition of insanity! </span>13 </pre> -<p>(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 <code><span class='Function'>F</span></code> with another variable. When we apply <code><span class='Function'>G</span></code>, the result of <code><span class='Function'>F</span></code> might change, but so does <code><span class='Function'>F1</span></code>! This effect is called <a href="https://en.wikipedia.org/wiki/Aliasing_(computing)">aliasing</a>.</p> +<p>(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 <a href="tacit.html">tacit</a> operation). Now suppose we share the value of <code><span class='Function'>F</span></code> with another variable like <code><span class='Function'>F1</span></code> below. When we apply <code><span class='Function'>G</span></code>, the result of <code><span class='Function'>F</span></code> might change, but so does <code><span class='Function'>F1</span></code>! This effect is called <a href="https://en.wikipedia.org/wiki/Aliasing_(computing)">aliasing</a>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=RjEg4oaQIEYKe/CdlY8gNn3CqCBG4oC/RjEKCkcgMwp78J2VjyA2fcKoIEbigL9GMQ==">↗️</a><pre> <span class='Function'>F1</span> <span class='Gets'>←</span> <span class='Function'>F</span> <span class='Brace'>{</span><span class='Function'>𝕏</span> <span class='Number'>6</span><span class='Brace'>}</span><span class='Modifier'>¨</span> <span class='Function'>F</span><span class='Ligature'>‿</span><span class='Function'>F1</span> ⟨ 14 14 ⟩ @@ -76,7 +76,7 @@ <span class='Brace'>{</span><span class='Function'>𝕏</span> <span class='Number'>6</span><span class='Brace'>}</span><span class='Modifier'>¨</span> <span class='Function'>F</span><span class='Ligature'>‿</span><span class='Function'>F1</span> ⟨ 9 9 ⟩ </pre> -<p>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. Comparison tells you whether two blocks are the same.</p> +<p>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.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ZiA9IGYx">↗️</a><pre> <span class='Value'>f</span> <span class='Function'>=</span> <span class='Value'>f1</span> 1 </pre> diff --git a/docs/doc/namespace.html b/docs/doc/namespace.html index ece4d6b6..8c4760af 100644 --- a/docs/doc/namespace.html +++ b/docs/doc/namespace.html @@ -5,7 +5,7 @@ </head> <div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div> <h1 id="namespaces"><a class="header" href="#namespaces">Namespaces</a></h1> -<p>A namespace is a type of value that groups together several values (fields) from the same scope. A block or file returns a namespace if it contains any export arrows <code><span class='Gets'>⇐</span></code> at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace can be mutable only if any of the code in it uses <code><span class='Gets'>↩</span></code> to change the value of a field.</p> +<p>A namespace is a type of value that groups together several variables (fields) from the same scope. A block or file returns a namespace if it contains any export arrows <code><span class='Gets'>⇐</span></code> at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace can be mutable only if any of its source code uses <code><span class='Gets'>↩</span></code> to change the value of a field.</p> <p>The following quick example shows a few ways to use a namespace returned by <code><span class='Function'>•Import</span></code>:</p> <pre><span class='Value'>ns</span> <span class='Gets'>←</span> <span class='Function'>•Import</span> <span class='String'>"file.bqn"</span> <span class='Bracket'>⟨</span><span class='Value'>something</span><span class='Separator'>,</span> <span class='Value'>abbr</span><span class='Gets'>⇐</span><span class='Value'>abbreviation</span><span class='Bracket'>⟩</span> <span class='Gets'>←</span> <span class='Value'>ns</span> <span class='Comment'># Destructure @@ -18,9 +18,9 @@ </span><span class='Function'>DoThing</span> <span class='Gets'>←</span> <span class='String'>"TODO"</span><span class='Modifier2'>⊸</span><span class='Function'>!</span> </pre> <h2 id="uses"><a class="header" href="#uses">Uses</a></h2> -<p>The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that <a href="lexical.html#closures">closures</a> provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't really expand the basic functionality of the language, but just make it easier to use.</p> +<p>The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that <a href="lexical.html#closures">closures</a> provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't expand the basic functionality of the language, but just make it easier to use.</p> <p>Namespaces improve encapsulation by allowing many values to be exported at once. With only one way to call them, functions and modifiers aren't such a good way to define a large part of a program. With a namespace you can define lots of things and expose exactly the ones you want to the rest of the world. For example, it's typical for files to define namespaces. A reader can see the exported values just by searching for <code><span class='Gets'>⇐</span></code>, and if you're nice, you might declare them all at the beginning of the file. Careful use of exports can guarantee that potentially dangerous functions are used correctly: if it's only valid to call function <code><span class='Function'>B</span></code> after function <code><span class='Function'>A</span></code> has been called, export <code><span class='Function'>AB</span><span class='Gets'>⇐</span><span class='Brace'>{</span><span class='Function'>A</span><span class='Value'>𝕩</span><span class='Separator'>⋄</span><span class='Function'>B</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code> and don't export <code><span class='Function'>B</span></code>.</p> -<p>Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain <code><span class='Gets'>↩</span></code>, as this is the only way it can modify the variables it contains.</p> +<p>Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain <code><span class='Gets'>↩</span></code>, as this is the only way it could modify the variables it contains.</p> <p>A namespace that makes use of mutability is essentially an object: a collection of state along with operations that act on it. <a href="oop.html">Object-oriented programming</a> is the other major use of namespaces. Contrary to the name, there's never a need to orient your programming around objects, and it's perfectly fine to use an object here or there when you need to, for instance to build a mutable queue of values.</p> <h2 id="exports"><a class="header" href="#exports">Exports</a></h2> <p>The double arrow <code><span class='Gets'>⇐</span></code> is used to export variables from a block or file, making the result a namespace instead of the result of the last line. There are two ways to export variables. First, <code><span class='Gets'>←</span></code> in the variable definition can be replaced with <code><span class='Gets'>⇐</span></code> to export the variable as it's defined. Second, an export statement consisting of an assignment target followed by <code><span class='Gets'>⇐</span></code>, with nothing to the right, exports the variables in the target and does nothing else. These export statements can be placed anywhere in the relevant program or body, including before declaration or on the last line, and a given variable can be exported any number of times. The block in the example below has two statements that export variables, exporting <code><span class='Value'>a</span></code>, <code><span class='Value'>b</span></code>, and <code><span class='Value'>c</span></code>.</p> @@ -32,18 +32,18 @@ <span class='Brace'>}</span> </pre> <h2 id="imports"><a class="header" href="#imports">Imports</a></h2> -<p>There are also two ways to get values out of a namespace, such as <code><span class='Value'>example</span></code> defined above. First, it might be used in a <a href="expression.html#destructuring">destructuring</a> assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like <code><span class='Value'>b</span></code>, which gives both, or an aliasing expression like <code><span class='Value'>b2</span><span class='Gets'>⇐</span><span class='Value'>b</span></code>. In this case, the value <code><span class='Value'>b</span></code> from the namespace is used, but it's given the name <code><span class='Value'>b2</span></code> instead of <code><span class='Value'>b</span></code>. Imported names can be repeated—but the variables defined can't—and all the names can be spelled with any role (the role is ignored).</p> +<p>There are also two ways to get values out of a namespace, such as <code><span class='Value'>example</span></code> defined above. First, one field at a time can be retrieved with dot syntax: write the namespace, then a dot <code><span class='Value'>.</span></code>, then another name.</p> +<pre><span class='Value'>example.b</span> + +<span class='Brace'>{</span><span class='Value'>n</span><span class='Gets'>⇐</span><span class='Number'>7</span><span class='Brace'>}</span><span class='Value'>.n</span> +</pre> +<p>The part on the left can be anything with a subject role, although it will often need to be parenthesized because <code><span class='Value'>.</span></code> has higher precedence than any operator. This allows it to be chained like <code><span class='Value'>a.b.c</span></code> if a namespace has a value that is also a namespace (and so on).</p> +<p>Second, a namespace might be used in a <a href="expression.html#destructuring">destructuring</a> assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like <code><span class='Value'>b</span></code>, which gives both, or an aliasing expression like <code><span class='Value'>b2</span><span class='Gets'>⇐</span><span class='Value'>b</span></code>. In this case, the value <code><span class='Value'>b</span></code> from the namespace is used, but it's given the name <code><span class='Value'>b2</span></code> instead of <code><span class='Value'>b</span></code>. Imported names can be repeated—but the variable names defined can't be—and all the names can be spelled with any role (the role is ignored).</p> <pre><span class='Bracket'>⟨</span><span class='Value'>alias</span><span class='Gets'>⇐</span><span class='Value'>a</span><span class='Separator'>,</span> <span class='Value'>b</span><span class='Separator'>,</span> <span class='Value'>c0</span><span class='Ligature'>‿</span><span class='Value'>c1</span><span class='Gets'>⇐</span><span class='Value'>c</span><span class='Separator'>,</span> <span class='Value'>b2</span><span class='Gets'>⇐</span><span class='Value'>b</span><span class='Bracket'>⟩</span> <span class='Gets'>←</span> <span class='Value'>example</span> </pre> <p>If aliasing with <code><span class='Gets'>⇐</span></code> is never used (or each use is parenthesized), the names can be given as a strand with <code><span class='Ligature'>‿</span></code>.</p> <pre><span class='Value'>c</span><span class='Ligature'>‿</span><span class='Value'>a</span> <span class='Gets'>←</span> <span class='Value'>example</span> </pre> -<p>The arrows <code><span class='Gets'>⇐</span></code> used for importing don't indicate that the surrounding block is a namespace or export variables. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is <code><span class='Gets'>⇐</span></code>.</p> +<p>The arrow <code><span class='Gets'>⇐</span></code> used for an alias doesn't export anything or indicate that its block is a namespace. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is <code><span class='Gets'>⇐</span></code>.</p> <pre><span class='Bracket'>⟨</span><span class='Value'>two</span><span class='Separator'>,</span> <span class='Value'>vars</span><span class='Bracket'>⟩</span> <span class='Gets'>⇐</span> <span class='Function'>•Import</span> <span class='String'>"stuff.bqn"</span> </pre> -<p>The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot <code><span class='Value'>.</span></code>, then another name.</p> -<pre><span class='Value'>example.b</span> - -<span class='Brace'>{</span><span class='Value'>n</span><span class='Gets'>⇐</span><span class='Number'>7</span><span class='Brace'>}</span><span class='Value'>.n</span> -</pre> -<p>The syntax is any subject followed by a dot and then a name. This can be chained like <code><span class='Value'>a.b.c</span></code> if a namespace has a value that is also a namespace (and so on).</p> diff --git a/docs/doc/transpose.html b/docs/doc/transpose.html index 952abc2c..807173ba 100644 --- a/docs/doc/transpose.html +++ b/docs/doc/transpose.html @@ -27,7 +27,7 @@ 3 </pre> <p>With two axes the only interesting operation of this sort is to swap them (and with one or zero axes there's nothing interesting to do, and <code><span class='Function'>⍉</span></code> just returns the argument array). But a BQN programmer may well want to work with higher-rank arrays—although such a programmer might call them "tensors"—and this means there are many more ways to rearrange the axes. Transpose extends to high-rank arrays to allow some useful special cases as well as completely general axis rearrangement, as described below.</p> -<h2 id="monadic-transpose"><a class="header" href="#monadic-transpose">Monadic Transpose</a></h2> +<h2 id="transposing-tensors"><a class="header" href="#transposing-tensors">Transposing tensors</a></h2> <p>APL extends matrix transposition to any rank by reversing all axes for its monadic <code><span class='Function'>⍉</span></code>, but this generalization isn't very natural and is almost never used. The main reason for it is to maintain the equivalence <code><span class='Value'>a</span> <span class='Function'>MP</span> <span class='Value'>b</span> <span class='Gets'>←→</span> <span class='Value'>b</span> <span class='Function'>MP</span><span class='Modifier2'>⌾</span><span class='Function'>⍉</span> <span class='Value'>a</span></code>, where <code><span class='Function'>MP</span> <span class='Gets'>←</span> <span class='Function'>+</span><span class='Modifier'>˝</span><span class='Modifier2'>∘</span><span class='Function'>×</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> is the generalized matrix product. But even here APL's Transpose is suspect. It does much more work than it needs to, as we'll see.</p> <p>BQN's transpose takes the first axis of <code><span class='Value'>𝕩</span></code> and moves it to the end.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIGEyMzQ1NiDihpAg4oaVMuKAvzPigL804oC/NeKAvzYKCuKJoiDijYkgYTIzNDU2">↗️</a><pre> <span class='Function'>≢</span> <span class='Value'>a23456</span> <span class='Gets'>←</span> <span class='Function'>↕</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span> |
