diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2022-04-11 22:32:10 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2022-04-11 22:32:56 -0400 |
| commit | 0fe07c5912c42fca1f4a9010d240ac0116a671a2 (patch) | |
| tree | cab3ac5af015ee7e579dd7cab994ce98c4d666ff /doc | |
| parent | 846425fabe9b4c5c9bbe2be0c785fd1662a0daaa (diff) | |
Documentation for Atop and Over
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/README.md | 1 | ||||
| -rw-r--r-- | doc/compose.md | 53 | ||||
| -rw-r--r-- | doc/primitive.md | 22 |
3 files changed, 65 insertions, 11 deletions
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 + +<!--GEN combinator.bqn +DrawComp ≍"∘○" +--> + +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). |
