From 8ad841e92f70fba73a5c778aa972186387f9ff5c Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Fri, 15 Apr 2022 19:23:10 -0400 Subject: Documentation for Before and After --- doc/README.md | 1 + doc/hook.md | 61 +++++++++++++++++ doc/primitive.md | 4 +- docs/doc/hook.html | 161 +++++++++++++++++++++++++++++++++++++++++++++ docs/doc/index.html | 1 + docs/doc/primitive.html | 4 +- docs/help/after_bind.html | 3 + docs/help/before_bind.html | 3 + help/after_bind.md | 3 + help/before_bind.md | 3 + 10 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 doc/hook.md create mode 100644 docs/doc/hook.html diff --git a/doc/README.md b/doc/README.md index 98c61d51..51b00436 100644 --- a/doc/README.md +++ b/doc/README.md @@ -42,6 +42,7 @@ Primitives: - [Array dimensions](shape.md) (`≢=≠`) - [Assert and Catch](assert.md) (`!` and `⎊`) - [Atop and Over](compose.md) (`∘○`) +- [Before and After](hook.md) (`⊸⟜`) - [Choose](choose.md) (`◶`) - [Constant](constant.md) (`˙`) - [Deshape and Reshape](reshape.md) (`⥊`) diff --git a/doc/hook.md b/doc/hook.md new file mode 100644 index 00000000..0eb5d5ce --- /dev/null +++ b/doc/hook.md @@ -0,0 +1,61 @@ +*View this file with results and syntax highlighting [here](https://mlochbaum.github.io/BQN/doc/hook.html).* + +# Before and After + +([This joke](https://aplwiki.com/wiki/File:Before_and_after.jpg) has already been claimed by APL, unfortunately) + +*Also see [this tutorial section](../tutorial/combinator.md#before-and-after) for an introduction that doesn't require so much context to understand.* + + + +The "hook" combinators Before and After serve a few purposes in BQN. The important thing to remember: the pointy side goes towards the first function to be executed, and the next function that returns the final result is at the ring side. If the pointy-side function is actually a constant like a number, then the ring-side function just gets applied to that constant and one of the arguments. This is the thing Haskell programmers are constantly telling each other isn't called currying, or "Bind" in BQN. + +| Name | `Cmp` | `Cmp 𝕩` | `𝕨 Cmp 𝕩` | Unified | Train +|--------|-------|------------|------------|--------------|-------- +| Before | `F⊸G` | `(F𝕩) G 𝕩` | `(F𝕨) G 𝕩` | `{(𝔽𝕨⊣𝕩)𝔾𝕩}` | `F∘⊣ G ⊢` +| After | `F⟜G` | `𝕩 F (G𝕩)` | `𝕨 F (G𝕩)` | `{(𝕨⊣𝕩)𝔽𝔾𝕩}` | `⊣ F G∘⊢` + +## Description + +In the general case, I think of Before as using `𝔽` as a preprocessing function applied to `𝕨` (when there are two arguments) and After as using `𝔾` as preprocessing for `𝕩`. Then the other operand is called on the result and remaining argument. Here are some simple calls with Pair (`⋈`): the result is a pair that corresponds to `𝕨‿𝕩`, but one or the other result has been modified by the pointy-side function. + + 9 √⊸⋈ 2 + + 9 ⋈⟜↕ 2 + +When only one argument is given, it's used in both positions, so that the arguments to the final function are `𝕩` and a function applied to `𝕩`. + + ⋈⟜↕ 5 + +This can be used to make a "filter" pattern using [Replicate](replicate.md) (`/`). The difference is that Replicate takes a list `𝕩` and boolean list `𝕨` indicating which elements to keep, but filter should take a list and a function that says whether to keep each element. The pattern is `F¨⊸/ x`, expanding to `(F¨x) / x`. Here's a list filtered with the function `{𝕩<0}`. + + {𝕩<0}¨⊸/ 4‿¯2‿1‿¯3‿¯3 + +As `<` is a pervasive function, there's no need for the Each (`¨`) in this case, and the clunky block function `{𝕩<0}` can also be written smaller with a combinator, as `<⟜0`. More on that in the next section… + + <⟜0⊸/ 4‿¯2‿1‿¯3‿¯3 + +## Bind + +"Bind" isn't a special case of Before and After, but instead a description of one way to use them. Let's take a look at the example from the previous section: + + <⟜0 4‿¯2‿1‿¯3‿¯3 + +If we expand `<⟜0 x`, we get `x < (0 x)`, which doesn't quite make sense. That's because `0` has a subject role, but `⟜` always applies its operands as functions. It's more accurate to use `x < (0{𝔽} x)`, or just skip ahead to `x < 0`. + +Similar reasoning gives the following expansions: + +| `Cmp` | `0⊸<` | `<⟜0` +|-----------|---------|--------- +| ` Cmp x` | `0 < x` | `x < 0` +| `w Cmp x` | `0 < x` | `w < 0` + +Note that when there are two arguments, the constant "swallows" the one on the same side, so that the function is applied to the constant and the argument on the *opposite* side. + +As in a train, if you want to use a function as a constant then you need to be explicity about it, with the [Constant](constant.md) (`˙`) modifier. + + 3 ⋈⟜(⌊˙)⊸⥊ 'a'+↕12 + +In the more extreme case of wanting a *modifier* operand, you might try `⋈⟜({∘}˙)⊸⥊`, or `(⊣⋈{∘}˙)⊸⥊`, or just cheat with `∾⟜⟨∘⟩⊸⥊`. diff --git a/doc/primitive.md b/doc/primitive.md index 79d6120b..f29dea71 100644 --- a/doc/primitive.md +++ b/doc/primitive.md @@ -71,8 +71,8 @@ Glyph | Name(s) | Definition | Description `˜` | [Self/Swap](swap.md) | `{𝕩𝔽𝕨⊣𝕩}` | 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 `𝔾` +`⊸` | [Before/Bind](hook.md) | `{(𝔽𝕨⊣𝕩)𝔾𝕩}` | `𝔾`'s left argument comes from `𝔽` +`⟜` | [After/Bind](hook.md) | `{(𝕨⊣𝕩)𝔽𝔾𝕩}` | `𝔽`'s right argument comes from `𝔾` `⌾` | Under | `{𝔾⁼∘𝔽○𝔾}` OR `{(𝔾𝕩)↩𝕨𝔽○𝔾𝕩⋄𝕩}` | Apply `𝔽` over `𝔾`, then undo `𝔾` `⊘` | [Valences](valences.md) | `{𝔽𝕩;𝕨𝔾𝕩}` | Apply `𝔽` if there's one argument but `𝔾` if there are two `◶` | [Choose](choose.md) | `{f←(𝕨𝔽𝕩)⊑𝕘 ⋄ 𝕨F𝕩}` | Select one of the functions in list `𝕘` based on `𝔽` diff --git a/docs/doc/hook.html b/docs/doc/hook.html new file mode 100644 index 00000000..22054800 --- /dev/null +++ b/docs/doc/hook.html @@ -0,0 +1,161 @@ + + + + BQN: Before and After + + +

Before and After

+

(This joke has already been claimed by APL, unfortunately)

+

Also see this tutorial section for an introduction that doesn't require so much context to understand.

+ + + + Before + + 𝔽𝔾 𝕩 + + + + + + + 𝔾 + 𝔽 + 𝕩 + + + 𝕨 𝔽𝔾 𝕩 + + + + + + + + 𝔾 + 𝔽 + 𝕨 + 𝕩 + + + + + After + + 𝔽𝔾 𝕩 + + + + + + + 𝔽 + 𝔾 + 𝕩 + + + 𝕨 𝔽𝔾 𝕩 + + + + + + + + 𝔽 + 𝔾 + 𝕨 + 𝕩 + + + + +

The "hook" combinators Before and After serve a few purposes in BQN. The important thing to remember: the pointy side goes towards the first function to be executed, and the next function that returns the final result is at the ring side. If the pointy-side function is actually a constant like a number, then the ring-side function just gets applied to that constant and one of the arguments. This is the thing Haskell programmers are constantly telling each other isn't called currying, or "Bind" in BQN.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCmpCmp 𝕩𝕨 Cmp 𝕩UnifiedTrain
BeforeFG(F𝕩) G 𝕩(F𝕨) G 𝕩{(𝔽𝕨𝕩)𝔾𝕩}F G
AfterFG𝕩 F (G𝕩)𝕨 F (G𝕩){(𝕨𝕩)𝔽𝔾𝕩} F G
+

Description

+

In the general case, I think of Before as using 𝔽 as a preprocessing function applied to 𝕨 (when there are two arguments) and After as using 𝔾 as preprocessing for 𝕩. Then the other operand is called on the result and remaining argument. Here are some simple calls with Pair (): the result is a pair that corresponds to 𝕨𝕩, but one or the other result has been modified by the pointy-side function.

+↗️
    9  2
+⟨ 3 2 ⟩
+
+    9  2
+⟨ 9 ⟨ 0 1 ⟩ ⟩
+
+

When only one argument is given, it's used in both positions, so that the arguments to the final function are 𝕩 and a function applied to 𝕩.

+↗️
     5
+⟨ 5 ⟨ 0 1 2 3 4 ⟩ ⟩
+
+

This can be used to make a "filter" pattern using Replicate (/). The difference is that Replicate takes a list 𝕩 and boolean list 𝕨 indicating which elements to keep, but filter should take a list and a function that says whether to keep each element. The pattern is F¨/ x, expanding to (F¨x) / x. Here's a list filtered with the function {𝕩<0}.

+↗️
    {𝕩<0}¨/ 4¯21¯3¯3
+⟨ ¯2 ¯3 ¯3 ⟩
+
+

As < is a pervasive function, there's no need for the Each (¨) in this case, and the clunky block function {𝕩<0} can also be written smaller with a combinator, as <0. More on that in the next section…

+↗️
    <0/ 4¯21¯3¯3
+⟨ ¯2 ¯3 ¯3 ⟩
+
+

Bind

+

"Bind" isn't a special case of Before and After, but instead a description of one way to use them. Let's take a look at the example from the previous section:

+↗️
    <0  4¯21¯3¯3
+⟨ 0 1 0 1 1 ⟩
+
+

If we expand <0 x, we get x < (0 x), which doesn't quite make sense. That's because 0 has a subject role, but always applies its operands as functions. It's more accurate to use x < (0{𝔽} x), or just skip ahead to x < 0.

+

Similar reasoning gives the following expansions:

+ + + + + + + + + + + + + + + + + + + + +
Cmp0<<0
Cmp x0 < xx < 0
w Cmp x0 < xw < 0
+

Note that when there are two arguments, the constant "swallows" the one on the same side, so that the function is applied to the constant and the argument on the opposite side.

+

As in a train, if you want to use a function as a constant then you need to be explicity about it, with the Constant (˙) modifier.

+↗️
    3 (˙) 'a'+↕12
+┌─      
+╵"abcd  
+  efgh  
+  ijkl" 
+       ┘
+
+

In the more extreme case of wanting a modifier operand, you might try ({}˙), or (⊣⋈{}˙), or just cheat with .

diff --git a/docs/doc/index.html b/docs/doc/index.html index 66bdbfec..82af1d4c 100644 --- a/docs/doc/index.html +++ b/docs/doc/index.html @@ -48,6 +48,7 @@
  • Array dimensions (≢=≠)
  • Assert and Catch (! and )
  • Atop and Over (∘○)
  • +
  • Before and After (⊸⟜)
  • Choose ()
  • Constant (˙)
  • Deshape and Reshape ()
  • diff --git a/docs/doc/primitive.html b/docs/doc/primitive.html index aa3fd087..fd153f5a 100644 --- a/docs/doc/primitive.html +++ b/docs/doc/primitive.html @@ -449,13 +449,13 @@ -Before/Bind +Before/Bind {(𝔽𝕨𝕩)𝔾𝕩} 𝔾's left argument comes from 𝔽 -After/Bind +After/Bind {(𝕨𝕩)𝔽𝔾𝕩} 𝔽's right argument comes from 𝔾 diff --git a/docs/help/after_bind.html b/docs/help/after_bind.html index 8ef227af..490f105e 100644 --- a/docs/help/after_bind.html +++ b/docs/help/after_bind.html @@ -6,6 +6,7 @@

    Left Multimap ()

    𝔽𝕘 𝕩: Bind

    +

    →full documentation

    Supply 𝕘 as a right argument to 𝔽 (𝕩 𝔽 𝕘).

    𝕘 is a constant, 𝔽 must be dyadic.

    ↗️
        -3 9
    @@ -18,6 +19,7 @@
     6
     

    𝔽𝔾 𝕩: After

    +

    →full documentation

    Apply 𝔾 to 𝕩, and supply it as a right argument to 𝔽 (𝕩 𝔽 (𝔾 𝕩)).

    𝔽 must be dyadic, 𝔾 must be monadic.

    ↗️
        ×- 9
    @@ -30,6 +32,7 @@
     ¯81
     

    𝕨 𝔽𝔾 𝕩: Dyadic After

    +

    →full documentation

    Apply 𝔾 to 𝕩, and supply it as a right argument to 𝔽 (𝕨 𝔽 (𝔾 𝕩)).

    𝔽 must be dyadic, 𝔾 must be monadic.

    ↗️
        2 ×- 1
    diff --git a/docs/help/before_bind.html b/docs/help/before_bind.html
    index c9f0ca0b..d240921b 100644
    --- a/docs/help/before_bind.html
    +++ b/docs/help/before_bind.html
    @@ -6,6 +6,7 @@
     
     

    Multimap ()

    𝕗𝔾 𝕩: Bind Left

    +

    →full documentation

    Supply 𝕗 as a left argument to 𝔾 (𝕗 𝔾 𝕩).

    𝕗 is a constant, 𝔾 must be dyadic.

    ↗️
        3- 9
    @@ -15,6 +16,7 @@
     ¯6
     

    𝔽𝔾 𝕩: Before

    +

    →full documentation

    Apply 𝔽 to 𝕩, and supply it as a left argument to 𝔾 ((𝔽 𝕩) 𝔾 𝕩).

    𝔽 must be monadic, 𝔾 must be dyadic.

    ↗️
        -+ 9
    @@ -27,6 +29,7 @@
     0
     

    𝕨 𝔽𝔾 𝕩: Dyadic Before

    +

    →full documentation

    Apply 𝔽 to 𝕨, and supply it as a left argument to 𝔾 ((𝔽 𝕨) 𝔾 𝕩).

    𝔽 must be monadic, 𝔾 must be dyadic.

    ↗️
        2 -+ 1
    diff --git a/help/after_bind.md b/help/after_bind.md
    index b18cc729..727ed83e 100644
    --- a/help/after_bind.md
    +++ b/help/after_bind.md
    @@ -3,6 +3,7 @@
     # Left Multimap (`⟜`)
     
     ## `𝔽⟜𝕘 𝕩`: Bind
    +[→full documentation](../doc/hook.md#bind)
     
     Supply `𝕘` as a right argument to `𝔽` (`𝕩 𝔽 𝕘`).
     
    @@ -17,6 +18,7 @@ Supply `𝕘` as a right argument to `𝔽` (`𝕩 𝔽 𝕘`).
     
     
     ## `𝔽⟜𝔾 𝕩`: After
    +[→full documentation](../doc/hook.md)
     
     Apply `𝔾` to `𝕩`, and supply it as a right argument to `𝔽` (`𝕩 𝔽 (𝔾 𝕩)`).
     
    @@ -31,6 +33,7 @@ Apply `𝔾` to `𝕩`, and supply it as a right argument to `𝔽` (`𝕩 𝔽
     
     
     ## `𝕨 𝔽⟜𝔾 𝕩`: Dyadic After
    +[→full documentation](../doc/hook.md)
     
     Apply `𝔾` to `𝕩`, and supply it as a right argument to `𝔽` (`𝕨 𝔽 (𝔾 𝕩)`).
     
    diff --git a/help/before_bind.md b/help/before_bind.md
    index 78073413..403e7092 100644
    --- a/help/before_bind.md
    +++ b/help/before_bind.md
    @@ -3,6 +3,7 @@
     # Multimap (`⊸`)
     
     ## `𝕗⊸𝔾 𝕩`: Bind Left
    +[→full documentation](../doc/hook.md#bind)
     
     Supply `𝕗` as a left argument to `𝔾` (`𝕗 𝔾 𝕩`).
     
    @@ -15,6 +16,7 @@ Supply `𝕗` as a left argument to `𝔾` (`𝕗 𝔾 𝕩`).
     
     
     ## `𝔽⊸𝔾 𝕩`: Before
    +[→full documentation](../doc/hook.md)
     
     Apply `𝔽` to `𝕩`, and supply it as a left argument to `𝔾` (`(𝔽 𝕩) 𝔾 𝕩`).
     
    @@ -29,6 +31,7 @@ Apply `𝔽` to `𝕩`, and supply it as a left argument to `𝔾` (`(𝔽 𝕩)
     
     
     ## `𝕨 𝔽⊸𝔾 𝕩`: Dyadic Before
    +[→full documentation](../doc/hook.md)
     
     Apply `𝔽` to `𝕨`, and supply it as a left argument to `𝔾` (`(𝔽 𝕨) 𝔾 𝕩`).
     
    -- 
    cgit v1.2.3