From 0fe07c5912c42fca1f4a9010d240ac0116a671a2 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Mon, 11 Apr 2022 22:32:10 -0400 Subject: Documentation for Atop and Over --- doc/README.md | 1 + doc/compose.md | 53 ++++++++++++++++++ doc/primitive.md | 22 ++++---- docs/doc/compose.html | 140 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/doc/index.html | 1 + docs/doc/primitive.html | 4 +- docs/help/atop.html | 2 + docs/help/over.html | 2 + help/atop.md | 2 + help/over.md | 2 + 10 files changed, 216 insertions(+), 13 deletions(-) create mode 100644 doc/compose.md create mode 100644 docs/doc/compose.html diff --git a/doc/README.md b/doc/README.md index 4d7e41a6..4f8c49cf 100644 --- a/doc/README.md +++ b/doc/README.md @@ -41,6 +41,7 @@ Primitives: - [Array depth](depth.md) (`≡` and `⚇`) - [Array dimensions](shape.md) (`≢=≠`) - [Assert and Catch](assert.md) (`!` and `⎊`) +- [Atop and Over](compose.md) (`∘○`) - [Deshape and Reshape](reshape.md) (`⥊`) - [Enclose](enclose.md) (`<`) - [Find](find.md) (`⍷`) diff --git a/doc/compose.md b/doc/compose.md new file mode 100644 index 00000000..c848b9d5 --- /dev/null +++ b/doc/compose.md @@ -0,0 +1,53 @@ +*View this file with results and syntax highlighting [here](https://mlochbaum.github.io/BQN/doc/compose.html).* + +# Atop and Over + + + +Atop and Over are 2-modifiers that extend the idea of "apply this, then that" in two different ways. They're modelled after the mathematical notation f∘g to compose two functions, and both do the same thing when there's one argument: `F∘G x` or `F○G x` is `F G x`. + +| `Cmp` | `Cmp 𝕩` | `𝕨 Cmp 𝕩` | Unified | On list +|-------|---------|:--------------:|:-----------:|:-------: +| `F∘G` | `F G 𝕩` | `F 𝕨 G 𝕩` | `{𝔽𝕨𝔾𝕩}` | `F G´𝕩` +| `F○G` | `F G 𝕩` | `(G 𝕨) F G 𝕩` | `{(𝔾𝕨)𝔽𝔾𝕩}` | `F´G¨𝕩` + +When there are two arguments, we might say Atop treats the right operand `𝔾` as primary and Over treats `𝔽` as primary—the primary operand becomes dyadic while the other is always monadic. Atop applies `𝔾` directly, making it more like mathematical composition if we suppose that `𝔾` is a function that can take a pair of arguments. Over instead makes two calls to apply `𝔾` separately to both arguments, then passes the results to `𝔽`. + +## Atop + +Of the two modifiers on this page, Atop is more common but less impactful. The composition `F∘G` is equivalent to the 2-[train](train.md) `F G` (the trains page has hints on when you'd choose one or the other). Its definition `{F𝕨G𝕩}` means that `G` is applied to one or two arguments and `F` is applied monadically to the result. It could be considered a "default way" to compose two functions. Keeps [tacit](tacit.md) programming syntax running smoothly, without making noise about it. Not like that busybody `⊸`. Some examples: + +`↕∘≠` is useful with one argument: `↕≠l` is a list of indices for `l`. + +`⌊∘÷` is useful with two arguments: `⌊a÷b` is the integer part when dividing `a` by `b`, often paired with the [remainder](arithmetic.md#additional-arithmetic) `b|a`. + +`⊔∘⊐` is useful with one or two arguments. From right to left, we have [Classify](selfcmp.md#classify)/[Index-of](search.md#index-of) (`⊐`) to convert values to indices, and [Group Indices](group.md) to group the indices. Er, that sounds good but what it *actually* does is to group indices of Group's argument, which correspond to indices of the original `𝕩`, according to their values as returned by `⊐`. Without a left argument, this means indices of `𝕩` are grouped corresponding to `⍷𝕩`, and if `𝕨` is provided the groups correspond to `𝕨` instead. + + ⊔∘⊐ "bbeabee" + + "abcde" ⊔∘⊐ "bbeabee" + +## Over + +Once you get used to Over, it's painful to go without it. I'd use it all the time in C if I could. + +Usually Over is used just for the dyadic meaning. If you have a composition that only works with one argument it's typical to write it with Atop (`∘`). And cases that work with one or two arguments do come up from time to time, but they're fairly rare, so the examples below are just for two arguments. + +A classic is the function `≡○∧`, which tests whether `𝕨` is a reordering of `𝕩`. The idea is to sort both arrays with `∧` to remove the ordering information + + "BQN" ≡○∧ "QNB" + "BQN" ≡○∧ "BBQ" + +Another example is `/○⥊`, used to filter elements in a high-rank array. Alone, `/` won't do this because there's no automatic choice of ordering for the results. Applying [Deshape](reshape.md) (`⥊`) to both chooses index order. + + ⊢ a ← "qBrs"≍"QtuN" + + a < 'a' # Capital letters + + (a<'a') / a # Not allowed + + (a<'a') /○⥊ a + +Over is closely connected with the Under modifier, which performs all the same steps but then undoes `𝔾` afterwards. diff --git a/doc/primitive.md b/doc/primitive.md index d81188c2..03634235 100644 --- a/doc/primitive.md +++ b/doc/primitive.md @@ -65,17 +65,17 @@ Functions that have significant differences from APL equivalents or don't appear *Combinators* only control the application of functions. Because a non-function operand applies as a constant function, some combinators have extra meanings when passed a constant. For example, `0˜` is identical to `0˙`—a constant function that always returns 0—and `0⊸<` is the function that tests whether its right argument is greater than 0. -Glyph | Name(s) | Definition | Description -------|-------------|--------------------------------|--------------------------------------- -`˙` | Constant | `{𝕩⋄𝕗}` | Return a function that returns the operand -`˜` | Self/Swap | `{𝕩𝔽𝕨⊣𝕩}` | Duplicate one argument or exchange two -`∘` | Atop | `{𝔽𝕨𝔾𝕩}` | Apply `𝔾` to both arguments and `𝔽` to the result -`○` | Over | `{(𝔾𝕨)𝔽𝔾𝕩}` | Apply `𝔾` to each argument and `𝔽` to the results -`⊸` | Before/Bind | `{(𝔽𝕨⊣𝕩)𝔾𝕩}` | `𝔾`'s left argument comes from `𝔽` -`⟜` | After/Bind | `{(𝕨⊣𝕩)𝔽𝔾𝕩}` | `𝔽`'s right argument comes from `𝔾` -`⌾` | Under | `{𝔾⁼∘𝔽○𝔾}` OR `{(𝔾𝕩)↩𝕨𝔽○𝔾𝕩⋄𝕩}` | Apply `𝔽` over `𝔾`, then undo `𝔾` -`⊘` | Valences | `{𝔽𝕩;𝕨𝔾𝕩}` | Apply `𝔽` if there's one argument but `𝔾` if there are two -`◶` | Choose | `{f←(𝕨𝔽𝕩)⊑𝕘 ⋄ 𝕨F𝕩}` | Select one of the functions in list `𝕘` based on `𝔽` +Glyph | Name(s) | Definition | Description +------|--------------------|--------------------------------|--------------------------------------- +`˙` | Constant | `{𝕩⋄𝕗}` | Return a function that returns the operand +`˜` | Self/Swap | `{𝕩𝔽𝕨⊣𝕩}` | Duplicate one argument or exchange two +`∘` | [Atop](compose.md) | `{𝔽𝕨𝔾𝕩}` | Apply `𝔾` to both arguments and `𝔽` to the result +`○` | [Over](compose.md) | `{(𝔾𝕨)𝔽𝔾𝕩}` | Apply `𝔾` to each argument and `𝔽` to the results +`⊸` | Before/Bind | `{(𝔽𝕨⊣𝕩)𝔾𝕩}` | `𝔾`'s left argument comes from `𝔽` +`⟜` | After/Bind | `{(𝕨⊣𝕩)𝔽𝔾𝕩}` | `𝔽`'s right argument comes from `𝔾` +`⌾` | Under | `{𝔾⁼∘𝔽○𝔾}` OR `{(𝔾𝕩)↩𝕨𝔽○𝔾𝕩⋄𝕩}` | Apply `𝔽` over `𝔾`, then undo `𝔾` +`⊘` | Valences | `{𝔽𝕩;𝕨𝔾𝕩}` | Apply `𝔽` if there's one argument but `𝔾` if there are two +`◶` | Choose | `{f←(𝕨𝔽𝕩)⊑𝕘 ⋄ 𝕨F𝕩}` | Select one of the functions in list `𝕘` based on `𝔽` Choose isn't really a combinator since it calls the function `⊑`, and Under is not a true combinator since it has an "undo" step at the end. This step might be implemented using the left operand's inverse (*computational* Under) or its structural properties (*structural* Under). diff --git a/docs/doc/compose.html b/docs/doc/compose.html new file mode 100644 index 00000000..4458ea3c --- /dev/null +++ b/docs/doc/compose.html @@ -0,0 +1,140 @@ + + + + BQN: Atop and Over + + +

Atop and Over

+ + + + Atop + + 𝔽𝔾 𝕩 + + + + + + 𝔽 + 𝔾 + 𝕩 + + + 𝕨 𝔽𝔾 𝕩 + + + + + + + + 𝔽 + 𝔾 + 𝕨 + 𝕩 + + + + + Over + + 𝔽𝔾 𝕩 + + + + + + 𝔽 + 𝔾 + 𝕩 + + + 𝕨 𝔽𝔾 𝕩 + + + + + + + + + + 𝔽 + 𝔾 + 𝔾 + 𝕨 + 𝕩 + + + + +

Atop and Over are 2-modifiers that extend the idea of "apply this, then that" in two different ways. They're modelled after the mathematical notation f∘g to compose two functions, and both do the same thing when there's one argument: FG x or FG x is F G x.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CmpCmp 𝕩𝕨 Cmp 𝕩UnifiedOn list
FGF G 𝕩F 𝕨 G 𝕩{𝔽𝕨𝔾𝕩}F G´𝕩
FGF G 𝕩(G 𝕨) F G 𝕩{(𝔾𝕨)𝔽𝔾𝕩}F´G¨𝕩
+

When there are two arguments, we might say Atop treats the right operand 𝔾 as primary and Over treats 𝔽 as primary—the primary operand becomes dyadic while the other is always monadic. Atop applies 𝔾 directly, making it more like mathematical composition if we suppose that 𝔾 is a function that can take a pair of arguments. Over instead makes two calls to apply 𝔾 separately to both arguments, then passes the results to 𝔽.

+

Atop

+

Of the two modifiers on this page, Atop is more common but less impactful. The composition FG is equivalent to the 2-train F G (the trains page has hints on when you'd choose one or the other). Its definition {F𝕨G𝕩} means that G is applied to one or two arguments and F is applied monadically to the result. It could be considered a "default way" to compose two functions. Keeps tacit programming syntax running smoothly, without making noise about it. Not like that busybody . Some examples:

+

is useful with one argument: ↕≠l is a list of indices for l.

+

÷ is useful with two arguments: a÷b is the integer part when dividing a by b, often paired with the remainder b|a.

+

is useful with one or two arguments. From right to left, we have Classify/Index-of () to convert values to indices, and Group Indices to group the indices. Er, that sounds good but what it actually does is to group indices of Group's argument, which correspond to indices of the original 𝕩, according to their values as returned by . Without a left argument, this means indices of 𝕩 are grouped corresponding to 𝕩, and if 𝕨 is provided the groups correspond to 𝕨 instead.

+↗️
     "bbeabee"
+⟨ ⟨ 0 1 4 ⟩ ⟨ 2 5 6 ⟩ ⟨ 3 ⟩ ⟩
+
+    "abcde"  "bbeabee"
+⟨ ⟨ 3 ⟩ ⟨ 0 1 4 ⟩ ⟨⟩ ⟨⟩ ⟨ 2 5 6 ⟩ ⟩
+
+

Over

+

Once you get used to Over, it's painful to go without it. I'd use it all the time in C if I could.

+

Usually Over is used just for the dyadic meaning. If you have a composition that only works with one argument it's typical to write it with Atop (). And cases that work with one or two arguments do come up from time to time, but they're fairly rare, so the examples below are just for two arguments.

+

A classic is the function , which tests whether 𝕨 is a reordering of 𝕩. The idea is to sort both arrays with to remove the ordering information

+↗️
    "BQN"  "QNB"
+1
+    "BQN"  "BBQ"
+0
+
+

Another example is /, used to filter elements in a high-rank array. Alone, / won't do this because there's no automatic choice of ordering for the results. Applying Deshape () to both chooses index order.

+↗️
     a  "qBrs""QtuN"
+┌─      
+╵"qBrs  
+  QtuN" 
+       ┘
+
+    a < 'a'  # Capital letters
+┌─         
+╵ 0 1 0 0  
+  1 0 0 1  
+          ┘
+
+    (a<'a') / a  # Not allowed
+Error: 𝕨/𝕩: Components of 𝕨 must have rank 0 or 1
+
+    (a<'a') / a
+"BQN"
+
+

Over is closely connected with the Under modifier, which performs all the same steps but then undoes 𝔾 afterwards.

diff --git a/docs/doc/index.html b/docs/doc/index.html index 49567105..821de18a 100644 --- a/docs/doc/index.html +++ b/docs/doc/index.html @@ -47,6 +47,7 @@
  • Array depth ( and )
  • Array dimensions (≢=≠)
  • Assert and Catch (! and )
  • +
  • Atop and Over (∘○)
  • Deshape and Reshape ()
  • Enclose (<)
  • Find ()
  • diff --git a/docs/doc/primitive.html b/docs/doc/primitive.html index 4def02cf..dda31281 100644 --- a/docs/doc/primitive.html +++ b/docs/doc/primitive.html @@ -437,13 +437,13 @@ -Atop +Atop {𝔽𝕨𝔾𝕩} Apply 𝔾 to both arguments and 𝔽 to the result -Over +Over {(𝔾𝕨)𝔽𝔾𝕩} Apply 𝔾 to each argument and 𝔽 to the results diff --git a/docs/help/atop.html b/docs/help/atop.html index 02764808..04827555 100644 --- a/docs/help/atop.html +++ b/docs/help/atop.html @@ -6,6 +6,7 @@

    Ring Operator ()

    𝔽𝔾 𝕩: Atop

    +

    →full documentation

    Apply 𝔾 to 𝕩, then apply 𝔽 (𝔽 𝔾 𝕩).

    𝔽 and 𝔾 must be monadic.

    ↗️
        -- 5
    @@ -15,6 +16,7 @@
     5
     

    𝕨 𝔽𝔾 𝕩: Dyadic Atop

    +

    →full documentation

    Apply 𝔾 to 𝕨 and 𝕩, then apply 𝔽 (𝔽 (𝕨 𝔾 𝕩)).

    𝔽 must be monadic, and 𝔾 must be dyadic.

    ↗️
        1 -+ 2
    diff --git a/docs/help/over.html b/docs/help/over.html
    index 8fe4c1eb..f7c86560 100644
    --- a/docs/help/over.html
    +++ b/docs/help/over.html
    @@ -6,6 +6,7 @@
     
     

    Circle ()

    𝔽𝔾 𝕩: Atop

    +

    →full documentation

    Apply 𝔾 to 𝕩, then apply 𝔽 (𝔽 𝔾 𝕩).

    𝔽 and 𝔾 must be monadic.

    ↗️
        -- 5
    @@ -15,6 +16,7 @@
     5
     

    𝕨 𝔽𝔾 𝕩: Over

    +

    →full documentation

    Apply 𝔾 to 𝕨 and 𝕩, then apply 𝔽 to them ((𝔾 𝕨) 𝔽 (𝔾 𝕩)).

    𝔽 must be dyadic, 𝔾 must be monadic.

    ↗️
        1 +- 2
    diff --git a/help/atop.md b/help/atop.md
    index 1f141483..cd1204ed 100644
    --- a/help/atop.md
    +++ b/help/atop.md
    @@ -3,6 +3,7 @@
     # Ring Operator (`∘`)
     
     ## `𝔽∘𝔾 𝕩`: Atop
    +[→full documentation](../doc/compose.md)
     
     Apply `𝔾` to `𝕩`, then apply `𝔽` (`𝔽 𝔾 𝕩`).
     
    @@ -15,6 +16,7 @@ Apply `𝔾` to `𝕩`, then apply `𝔽` (`𝔽 𝔾 𝕩`).
     
     
     ## `𝕨 𝔽∘𝔾 𝕩`: Dyadic Atop
    +[→full documentation](../doc/compose.md)
     
     Apply `𝔾` to `𝕨` and `𝕩`, then apply `𝔽` (`𝔽 (𝕨 𝔾 𝕩)`).
     
    diff --git a/help/over.md b/help/over.md
    index 3a9022ae..c915a207 100644
    --- a/help/over.md
    +++ b/help/over.md
    @@ -3,6 +3,7 @@
     # Circle (`○`)
     
     ## `𝔽○𝔾 𝕩`: Atop
    +[→full documentation](../doc/compose.md)
     
     Apply `𝔾` to `𝕩`, then apply `𝔽` (`𝔽 𝔾 𝕩`).
     
    @@ -15,6 +16,7 @@ Apply `𝔾` to `𝕩`, then apply `𝔽` (`𝔽 𝔾 𝕩`).
     
     
     ## `𝕨 𝔽○𝔾 𝕩`: Over
    +[→full documentation](../doc/compose.md)
     
     Apply `𝔾` to `𝕨` and `𝕩`, then apply `𝔽` to them (`(𝔾 𝕨) 𝔽 (𝔾 𝕩)`).
     
    -- 
    cgit v1.2.3