aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--commentary/problems.md2
-rw-r--r--doc/README.md1
-rw-r--r--doc/compose.md2
-rw-r--r--doc/constant.md2
-rw-r--r--doc/group.md2
-rw-r--r--doc/identity.md2
-rw-r--r--doc/primitive.md2
-rw-r--r--doc/replicate.md2
-rw-r--r--doc/reshape.md2
-rw-r--r--doc/scan.md2
-rw-r--r--doc/search.md2
-rw-r--r--doc/selfcmp.md2
-rw-r--r--doc/under.md78
-rw-r--r--doc/undo.md4
-rw-r--r--docs/commentary/problems.html2
-rw-r--r--docs/doc/compose.html2
-rw-r--r--docs/doc/constant.html2
-rw-r--r--docs/doc/group.html2
-rw-r--r--docs/doc/identity.html2
-rw-r--r--docs/doc/index.html1
-rw-r--r--docs/doc/primitive.html2
-rw-r--r--docs/doc/replicate.html2
-rw-r--r--docs/doc/reshape.html2
-rw-r--r--docs/doc/scan.html2
-rw-r--r--docs/doc/search.html2
-rw-r--r--docs/doc/selfcmp.html2
-rw-r--r--docs/doc/under.html78
-rw-r--r--docs/doc/undo.html4
-rw-r--r--docs/help/under.html1
-rw-r--r--help/under.md1
30 files changed, 186 insertions, 26 deletions
diff --git a/commentary/problems.md b/commentary/problems.md
index af37a869..36d7cc58 100644
--- a/commentary/problems.md
+++ b/commentary/problems.md
@@ -52,7 +52,7 @@ If you include multiple multi-line functions in what would otherwise be a one-li
If you have the normal mix of monads and dyads you'll need a lot of parentheses and might end up abusing `⟜`. Largely solved with the Nothing syntax `·`, which acts like J's Cap (`[:`) in a train, but still a minor frustration.
### Under/bind combination is awkward
-It's most common to use Under with dyadic structural functions in the form `…⌾(i⊸F)`, for example where `F` is one of `/` or `↑`. This is frustrating for two reasons: it requires parentheses, and it doesn't allow `i` to be computed tacitly. If there's no left argument then the modifier `{𝔽⌾(𝕨⊸𝔾)𝕩}` can be more useful, but it doesn't cover some useful cases such as mask `a ⊣⌾(u⊸/) b`.
+It's most common to use Under with dyadic structural functions in the form `…⌾(i⊸F)`, for example where `F` is one of `/` or `↑`. This is frustrating for two reasons: it requires parentheses, and it doesn't allow `i` to be computed tacitly. If there's no left argument then the modifier `{𝔽⌾(𝕨⊸𝔾)𝕩}` can be more useful, but it doesn't cover some useful cases such as mask `a ⊣⌾(u⊸/) b`. Another form of Under that's sometimes wanted is `{𝕨⊸𝔽⌾𝔾𝕩}`. One modifier can only do so much.
### List splicing is fiddly
It's common when manipulating text to want to replace a slice with a different slice with an unrelated length. Structural Under works well for this if the new slice has the same length but doesn't otherwise (an implementation could choose to support it, but *only* if the slice is extracted using two Drops, not Take). So in general the programmer has to cut off initial and final segments and join them to the new slice. If the new slice is computed from the old one it's much worse, as there will be duplication between the code to extract that slice and the other segments. The duplication can be avoided with Group using `∾F⌾(1⊸⊑)(s‿e⍋↕∘≠)⊸⊔`, but this is a lot of work and will execute slowly without some special support. In fact, everything here is liable to run slowly, making too many copies of the unmodified part of the stream.
diff --git a/doc/README.md b/doc/README.md
index f0db0011..110482f2 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -72,6 +72,7 @@ Primitives:
- [Solo, Couple, and Merge: `≍>`](couple.md)
- [Take and Drop: `↑`](take.md)
- [Transpose: `⍉`](transpose.md)
+- [Under: `⌾`](under.md)
- [Undo: `⁼`](undo.md)
- [Valences: `⊘`](valences.md)
- [Windows: `↕`](windows.md)
diff --git a/doc/compose.md b/doc/compose.md
index c848b9d5..9c8c2106 100644
--- a/doc/compose.md
+++ b/doc/compose.md
@@ -50,4 +50,4 @@ Another example is `/○⥊`, used to filter elements in a high-rank array. Alon
(a<'a') /○⥊ a
-Over is closely connected with the Under modifier, which performs all the same steps but then undoes `𝔾` afterwards.
+Over is closely connected with the [Under](under.md) modifier, which performs all the same steps but then undoes `𝔾` afterwards.
diff --git a/doc/constant.md b/doc/constant.md
index 73413a03..55c95f82 100644
--- a/doc/constant.md
+++ b/doc/constant.md
@@ -23,6 +23,6 @@ When programming with [first-class functions](functional.md), the constant appli
M ← -
m {𝕨⌾(2⊸⊑) 𝕩} 1‿2‿3‿4
-Here `m` is applied to `2⊑𝕩` even though we want to discard that value. Spelled as `m`, our [context-free grammar](context.md) knows it's a function argument, but this [doesn't affect](../problems.md#syntactic-type-erasure) later usage. Under always applies `𝔽` as a function. The proper definition of the insertion function should use a `˙`, like this:
+Here `m` is applied to `2⊑𝕩` even though we want to discard that value. Spelled as `m`, our [context-free grammar](context.md) knows it's a function argument, but this [doesn't affect](../problems.md#syntactic-type-erasure) later usage. [Under](under.md) always applies `𝔽` as a function. The proper definition of the insertion function should use a `˙`, like this:
m {𝕨˙⌾(2⊸⊑) 𝕩} 1‿2‿3‿4
diff --git a/doc/group.md b/doc/group.md
index aceea8ed..7156c24b 100644
--- a/doc/group.md
+++ b/doc/group.md
@@ -151,7 +151,7 @@ To avoid including spaces in the result, we should change the result index at ea
' '((⊢-˜¬×+`)∘=⊔⊢)"BQN uses notation as a tool of thought"
-A function with structural Under, such as `` {¯1¨⌾(𝕩⊸/)+`𝕩} ``, would also work.
+A function with structural [Under](under.md), such as `` {¯1¨⌾(𝕩⊸/)+`𝕩} ``, would also work.
In other cases, we might want to split on spaces, so that words are separated by any number of spaces, and extra spaces don't affect the output. Currently our function makes a new word with each space:
diff --git a/doc/identity.md b/doc/identity.md
index 5876a885..e8682ea5 100644
--- a/doc/identity.md
+++ b/doc/identity.md
@@ -26,7 +26,7 @@ The right argument `↕5` could be any length-5 list, as its values aren't used.
(⌽↕4) ⊣¨ ↕4‿5
-A more powerful pattern is with dyadic Under (`⌾`): unselected parts of the result will use values from `𝕩`. If `𝔽` is `⊣`, then the selected ones will use values from `𝕨`, merging these arrays together.
+A more powerful pattern is with dyadic [Under](under.md) (`⌾`): unselected parts of the result will use values from `𝕩`. If `𝔽` is `⊣`, then the selected ones will use values from `𝕨`, merging these arrays together.
"ABCDE" ⊣⌾(0‿1‿1‿0‿0⊸/) "abcde"
diff --git a/doc/primitive.md b/doc/primitive.md
index f29dea71..a48d6602 100644
--- a/doc/primitive.md
+++ b/doc/primitive.md
@@ -73,7 +73,7 @@ Glyph | Name(s) | Definition | Description
`○` | [Over](compose.md) | `{(𝔾𝕨)𝔽𝔾𝕩}` | Apply `𝔾` to each argument and `𝔽` to the results
`⊸` | [Before/Bind](hook.md) | `{(𝔽𝕨⊣𝕩)𝔾𝕩}` | `𝔾`'s left argument comes from `𝔽`
`⟜` | [After/Bind](hook.md) | `{(𝕨⊣𝕩)𝔽𝔾𝕩}` | `𝔽`'s right argument comes from `𝔾`
-`⌾` | Under | `{𝔾⁼∘𝔽○𝔾}` OR `{(𝔾𝕩)↩𝕨𝔽○𝔾𝕩⋄𝕩}` | Apply `𝔽` over `𝔾`, then undo `𝔾`
+`⌾` | [Under](under.md) | `{𝔾⁼∘𝔽○𝔾}` 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/doc/replicate.md b/doc/replicate.md
index 426b6d2c..66905116 100644
--- a/doc/replicate.md
+++ b/doc/replicate.md
@@ -39,7 +39,7 @@ Ll ← Line∘⍉ ≍ + (0≍0.05×-○⊑)≍˘0.45‿¯0.55˙
The functions Indices and Replicate are used to copy or filter data. They might be described as transforming a [run-length encoding](https://en.wikipedia.org/wiki/Run-length_encoding) into unencoded form. On the other hand, Indices might be described as giving a sparse representation of `𝕩`, which is smaller if `𝕩` mostly consists of zeros.
-BQN doesn't have any of the various features used in APL to add fills to the result of Replicate, like negative numbers in `𝕨` or an Expand (`\`) primitive. An alternative to Expand is to use Replicate with structural Under (`⌾`) to insert values into an array of fills.
+BQN doesn't have any of the various features used in APL to add fills to the result of Replicate, like negative numbers in `𝕨` or an Expand (`\`) primitive. An alternative to Expand is to use Replicate with structural [Under](under.md) (`⌾`) to insert values into an array of fills.
## Replicate
diff --git a/doc/reshape.md b/doc/reshape.md
index fa939ce4..38bbe203 100644
--- a/doc/reshape.md
+++ b/doc/reshape.md
@@ -131,7 +131,7 @@ Computed Reshape might also be used in actual data processing: for example, to s
+´˘ ↑‿4 ⥊ ⟨0,2,1,1, 5,9,6,4, 3,3,3,3, 9,7⟩
-Computed Reshape can even be used with structural Under. Only the `∘` case really makes sense, although `⌊`, which leaves trailing elements unchanged, could conceivably be useful. Below, we split one argument into three groups and [reverse](reverse.md) their order, and reverse groups of three in another.
+Computed Reshape can even be used with [structural Under](under.md#structural-under). Only the `∘` case really makes sense, although `⌊`, which leaves trailing elements unchanged, could conceivably be useful. Below, we split one argument into three groups and [reverse](reverse.md) their order, and reverse groups of three in another.
⌽⌾(3‿∘⊸⥊) ↕15
diff --git a/doc/scan.md b/doc/scan.md
index 73ce3f0a..f87580e4 100644
--- a/doc/scan.md
+++ b/doc/scan.md
@@ -94,7 +94,7 @@ A more complicated boolean scan, which depends on the left-to-right ordering, is
## Reverse scan
-We've discussed how the scan moves forward along `𝕩`, so that each time `𝔽` takes an old result as `𝕨` and a new value as `𝕩`. This means that results correspond to [prefixes](prefixes.md) and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan Under [Reverse](reverse.md) (`` `⌾⌽ ``) does the trick.
+We've discussed how the scan moves forward along `𝕩`, so that each time `𝔽` takes an old result as `𝕨` and a new value as `𝕩`. This means that results correspond to [prefixes](prefixes.md) and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan [Under](under.md) [Reverse](reverse.md) (`` `⌾⌽ ``) does the trick.
∨` 0‿0‿1‿0‿0‿1‿0
diff --git a/doc/search.md b/doc/search.md
index 7c0aa7dd..af2c9e7e 100644
--- a/doc/search.md
+++ b/doc/search.md
@@ -135,7 +135,7 @@ Just as bad, this result has the right information, but is enclosed and could br
stuff ⊑∘⊐⟜< "string"
-If `𝕨` is fixed, then the version I prefer is to use Under to enclose the argument and then un-enclose the result. It requires `𝕨` to be bound to `⊐` because otherwise Under would enclose `𝕨` as well, since it applies `𝔾` to both arguments.
+If `𝕨` is fixed, then the version I prefer is to use [Under](under.md) to enclose the argument and then un-enclose the result. It requires `𝕨` to be bound to `⊐` because otherwise Under would enclose `𝕨` as well, since it applies `𝔾` to both arguments.
stuff⊸⊐⌾< "string"
diff --git a/doc/selfcmp.md b/doc/selfcmp.md
index 967f7974..41114a1d 100644
--- a/doc/selfcmp.md
+++ b/doc/selfcmp.md
@@ -131,7 +131,7 @@ A more efficient way when `⊒` doesn't have a fast implementation is `` /(¯1
*There's also an [APL Wiki page](https://aplwiki.com/wiki/Unique) on this function.*
-Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate Under Reverse (`⍷⌾⌽`) orders by last occurrence instead.
+Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate [Under](under.md) Reverse (`⍷⌾⌽`) orders by last occurrence instead.
⍷ >"take"‿"drop"‿"drop"‿"pick"‿"take"‿"take"
diff --git a/doc/under.md b/doc/under.md
index 23f7fe89..b7819f97 100644
--- a/doc/under.md
+++ b/doc/under.md
@@ -35,3 +35,81 @@ rdim ← 4‿4×d
-->
+
+The Under 2-modifier expresses the idea of modifying *part* of an array, or applying a function in a different domain, such as working in logarithmic space. It works with a transformation `𝔾` that applies to the original argument `𝕩`, and a function `𝔽` that applies to the result of `𝔾` (and if `𝕨` is given, `𝔾𝕨` is used as the left argument to `𝔽`). Under does the "same thing" as `𝔽`, but to the original argument, by applying `𝔾`, then `𝔽`, then undoing `𝔾` somehow.
+
+It's not always possible to undo `𝔾`, so only some right operands will work. BQN supports two cases. **Computational** Under tries the [Undo](undo.md) modifier, so that `𝔽⌾𝔾` is `𝔾⁼∘𝔽○𝔾`.
+
+ 3 +⌾(ט) 4 # Square root of sum of squares
+
+**Structural** Under is used when `𝔾` selects part of the array. BQN tracks what was selected and puts the results from `𝔽` back where they came from.
+
+ +`⌾∾ ⟨3‿1‿0, 2‿5, 0‿0‿6⟩ # Prefix sum, keeping structure
+
+Structural Under is an essential part of BQN because of how it can "change" an immutable [array](array.md), and it supports more functions and is always well defined. Computational Under's nice, but not so important. The reason they can both be supported as a single primitive is that they follow this unifying principle:
+
+ (𝔾 𝕨𝔽⌾𝔾𝕩) ≡ 𝕨𝔽○𝔾𝕩
+
+That is, when you apply `𝔽⌾𝔾` *before* applying `𝔾`, you get the value that comes from applying `𝔽` *after* `𝔾`. The definition of computational under comes from applying `𝔾⁼` to both sides and cancelling `𝔾⁼𝔾`, which solves the constraint but doesn't have to be a unique solution. For structural Under, the reason this works is that `𝔾` selects out the parts of `𝔽⌾𝔾` that were placed back in by Under. Other parts are defined to be the same as it was in `𝕩`, so the result is fully specified.
+
+## Structural Under
+
+A *structural function* is one that moves elements around without performing computation on them. It's okay if it performs computation, but it has to be based on the structure of its argument—shape, and element structure—and not on the values of atoms in it. As an example, the function `⊏˘` selects the first column of an array.
+
+ ⊢ a ← 4‿3⥊↕12
+
+ 1⊸⌽⌾(⊏˘) a
+
+When used with Under, the function `1⊸⌽` applies to the first column, rotating it. The result of `𝔽` needs to be compatible with the selection function, so Rotate works but trying to remove an element is no good:
+
+ 1⊸↓⌾(⊏˘) a
+
+BQN can detect lots of structural functions when written in [tacit](tacit.md) form; see the list of functions [in the spec](../spec/inferred.md#required-structural-inverses). You can also include computations on the shape. For example, here's a function to reverse the first half of a list.
+
+ ⌽⌾(⊢↑˜≠÷2˙) "abcdef"
+
+Under is useful with [scans](scan.md), as discussed in a section on [reverse scan](scan.md#reverse-scan). In this case, `⌽` is exactly invertible, so `⌾` can just as easily be seen as computational Under. When `𝔾` has an exact inverse, there can only be one solution to the constraint on Under, and both forms must be the same.
+
+ ∧`⌾⌽ 1‿0‿1‿0‿1‿1‿1
+
+## Computational Under
+
+Computational Under is based on [Undo](undo.md) (`⁼`), and applies whenever structural Under doesn't. It's still limited, because Undo doesn't work on many or even most functions. One common use is with the square function `ט`, for computations such as finding the magnitude of a vector, or a [root-mean-square](https://en.wikipedia.org/wiki/Root_mean_square) average like the one below.
+
+ (+´÷≠)⌾(ט) 2‿3‿4‿5
+
+This average is the square root of the average of the squares of the arguments, and `⌾` lets us combine the two square-y steps. Similarly, `⌾÷` can be used for a harmonic sum or mean (you might notice that computational Under is a lot more mathy than the structural one).
+
+Under is the idiomatic way to do a round-to-nearest function:
+
+ ⌊⌾(10⊸×) 3.524‿6.799‿2.031
+
+See how it works? `⌊` rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (single decimals are now integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... <20. If I had the right range `↕n`, then it would be `4+3×↕n`, or `(4+3×⊢)↕n`. By using the *inverse* of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic.
+
+ ↕∘⌈⌾((4+3×⊢)⁼) 20
+
+Well, really it's a bit of simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge.
+
+## Left argument
+
+When called dyadically, Under applies `𝔽` dyadically, like [Over](compose.md#over). This doesn't affect the undoing part of Under, which still tries to put the result of `𝔽` back into `𝕩` for structural Under or invert `𝔾` for computational. In fact, `𝕨 𝔽⌾𝔾 𝕩` is equivalent to `(𝔾𝕨)˙⊸𝔽⌾𝔾 𝕩` so no exciting language stuff is happening here at all.
+
+But you can still do some cool stuff with it! One pattern is simply to set `𝔽` to `⊣`, the [identity](identity.md) function that just returns its left argument. Now structural Under will replace everything that `𝔾` selects from `𝕩` with the corresponding values in `𝕨`. Here's an example that replaces elements with indices `1` and `2`.
+
+ "abcd" ⊣⌾(1‿2⊸⊏) "0123"
+
+This method can replace deeper structure too. Below, `𝔾` is `¯1⊑¨2↑⊢`, selecting the last element of each of the first two elements of its argument. The elements that aren't selected don't have to match up.
+
+ ⟨"ab", "cde", "fg"⟩ ⊣⌾(¯1⊑¨2↑⊢) ↕¨3‿2‿1‿1
+
+In fact, the elements that *are* selected don't really have to match up before being selected. So here's an example with [Join](join.md) where the same pattern is used to "re-flow" `𝕨` into the structure of `𝕩`.
+
+ ⟨"ab", "cde", "fg"⟩ ⊣⌾∾ ⟨"---", "----"⟩
+
+### And getting it not to do that
+
+The Over-based action on `𝕨` shows up more than you might think, but sometimes you just want to pass a left argument to `𝔽` without `𝔾` getting involved. In this case you have to [bind](hook.md#bind) it in: call `𝕨⊸𝔽⌾𝔾 𝕩`.
+
+ 1‿2‿3⊸+⌾(1‿1‿0‿1⊸/) 10‿20‿30‿40
+
+This [gets bad](../problems.md#underbind-combination-is-awkward) when you want `𝕨` to be an argument. In the worst case you might need to write out an operator `{𝕨⊸𝔽⌾𝔾𝕩}`.
diff --git a/doc/undo.md b/doc/undo.md
index 08099e8f..4afa2c00 100644
--- a/doc/undo.md
+++ b/doc/undo.md
@@ -2,7 +2,7 @@
# Undo
-Oh no, you've deleted a function after spending half an hour writing it! Well… hopefully your editor can help with that. But maybe you'll be interested to hear that BQN can reverse the action of some functions—ones that *don't* lose information. This capability is also used by [Repeat](repeat.md) (`⍟`) to repeat a negative number of times.
+Oh no, you've deleted a function after spending half an hour writing it! Well… hopefully your editor can help with that. But maybe you'll be interested to hear that BQN can reverse the action of some functions—ones that *don't* lose information. This capability is also used by [Repeat](repeat.md) (`⍟`) to repeat a negative number of times, and [Under](under.md) (`⌾`) in some cases.
2 ⌽ "abcde"
@@ -14,7 +14,7 @@ Above is one example of Undo (`⁼`) in action. [Rotate](reverse.md) shifts the
Fn⁼ Fn "BQN"
-Here it undoes a function to decrement the last character by incrementing that character. In part this is enabled by the clean design of BQN primitives, because better-behaved functions like those using structural Under are easier to invert.
+Here it undoes a function to decrement the last character by incrementing that character. In part this is enabled by the clean design of BQN primitives, because better-behaved functions like those using structural [Under](under.md) are easier to invert.
## The rules
diff --git a/docs/commentary/problems.html b/docs/commentary/problems.html
index ca964274..38d41ea9 100644
--- a/docs/commentary/problems.html
+++ b/docs/commentary/problems.html
@@ -37,7 +37,7 @@
<h3 id="trains-dont-like-monads"><a class="header" href="#trains-dont-like-monads">Trains don't like monads</a></h3>
<p>If you have the normal mix of monads and dyads you'll need a lot of parentheses and might end up abusing <code><span class='Modifier2'>⟜</span></code>. Largely solved with the Nothing syntax <code><span class='Nothing'>·</span></code>, which acts like J's Cap (<code><span class='Value'>[</span><span class='Head'>:</span></code>) in a train, but still a minor frustration.</p>
<h3 id="underbind-combination-is-awkward"><a class="header" href="#underbind-combination-is-awkward">Under/bind combination is awkward</a></h3>
-<p>It's most common to use Under with dyadic structural functions in the form <code><span class='Value'>…</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>i</span><span class='Modifier2'>⊸</span><span class='Function'>F</span><span class='Paren'>)</span></code>, for example where <code><span class='Function'>F</span></code> is one of <code><span class='Function'>/</span></code> or <code><span class='Function'>↑</span></code>. This is frustrating for two reasons: it requires parentheses, and it doesn't allow <code><span class='Value'>i</span></code> to be computed tacitly. If there's no left argument then the modifier <code><span class='Brace'>{</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>𝕨</span><span class='Modifier2'>⊸</span><span class='Function'>𝔾</span><span class='Paren'>)</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code> can be more useful, but it doesn't cover some useful cases such as mask <code><span class='Value'>a</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>u</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span> <span class='Value'>b</span></code>.</p>
+<p>It's most common to use Under with dyadic structural functions in the form <code><span class='Value'>…</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>i</span><span class='Modifier2'>⊸</span><span class='Function'>F</span><span class='Paren'>)</span></code>, for example where <code><span class='Function'>F</span></code> is one of <code><span class='Function'>/</span></code> or <code><span class='Function'>↑</span></code>. This is frustrating for two reasons: it requires parentheses, and it doesn't allow <code><span class='Value'>i</span></code> to be computed tacitly. If there's no left argument then the modifier <code><span class='Brace'>{</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>𝕨</span><span class='Modifier2'>⊸</span><span class='Function'>𝔾</span><span class='Paren'>)</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code> can be more useful, but it doesn't cover some useful cases such as mask <code><span class='Value'>a</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>u</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span> <span class='Value'>b</span></code>. Another form of Under that's sometimes wanted is <code><span class='Brace'>{</span><span class='Value'>𝕨</span><span class='Modifier2'>⊸</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>. One modifier can only do so much.</p>
<h3 id="list-splicing-is-fiddly"><a class="header" href="#list-splicing-is-fiddly">List splicing is fiddly</a></h3>
<p>It's common when manipulating text to want to replace a slice with a different slice with an unrelated length. Structural Under works well for this if the new slice has the same length but doesn't otherwise (an implementation could choose to support it, but <em>only</em> if the slice is extracted using two Drops, not Take). So in general the programmer has to cut off initial and final segments and join them to the new slice. If the new slice is computed from the old one it's much worse, as there will be duplication between the code to extract that slice and the other segments. The duplication can be avoided with Group using <code><span class='Function'>∾F</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>⊑</span><span class='Paren'>)(</span><span class='Value'>s</span><span class='Ligature'>‿</span><span class='Value'>e</span><span class='Function'>⍋↕</span><span class='Modifier2'>∘</span><span class='Function'>≠</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>⊔</span></code>, but this is a lot of work and will execute slowly without some special support. In fact, everything here is liable to run slowly, making too many copies of the unmodified part of the stream.</p>
<p>Dyalog's solution here (and dzaima/BQN's) is Regex, which is a nice feature but also an entire second language to learn.</p>
diff --git a/docs/doc/compose.html b/docs/doc/compose.html
index 4458ea3c..7a8da224 100644
--- a/docs/doc/compose.html
+++ b/docs/doc/compose.html
@@ -137,4 +137,4 @@
<span class='Paren'>(</span><span class='Value'>a</span><span class='Function'>&lt;</span><span class='String'>'a'</span><span class='Paren'>)</span> <span class='Function'>/</span><span class='Modifier2'>○</span><span class='Function'>⥊</span> <span class='Value'>a</span>
"BQN"
</pre>
-<p>Over is closely connected with the Under modifier, which performs all the same steps but then undoes <code><span class='Function'>𝔾</span></code> afterwards.</p>
+<p>Over is closely connected with the <a href="under.html">Under</a> modifier, which performs all the same steps but then undoes <code><span class='Function'>𝔾</span></code> afterwards.</p>
diff --git a/docs/doc/constant.html b/docs/doc/constant.html
index 524a13f5..d68235aa 100644
--- a/docs/doc/constant.html
+++ b/docs/doc/constant.html
@@ -49,7 +49,7 @@
<span class='Value'>m</span> <span class='Brace'>{</span><span class='Value'>𝕨</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>⊑</span><span class='Paren'>)</span> <span class='Value'>𝕩</span><span class='Brace'>}</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span>
⟨ 1 2 ¯3 4 ⟩
</pre>
-<p>Here <code><span class='Value'>m</span></code> is applied to <code><span class='Number'>2</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code> even though we want to discard that value. Spelled as <code><span class='Value'>m</span></code>, our <a href="context.html">context-free grammar</a> knows it's a function argument, but this <a href="../problems.html#syntactic-type-erasure">doesn't affect</a> later usage. Under always applies <code><span class='Function'>𝔽</span></code> as a function. The proper definition of the insertion function should use a <code><span class='Modifier'>˙</span></code>, like this:</p>
+<p>Here <code><span class='Value'>m</span></code> is applied to <code><span class='Number'>2</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code> even though we want to discard that value. Spelled as <code><span class='Value'>m</span></code>, our <a href="context.html">context-free grammar</a> knows it's a function argument, but this <a href="../problems.html#syntactic-type-erasure">doesn't affect</a> later usage. <a href="under.html">Under</a> always applies <code><span class='Function'>𝔽</span></code> as a function. The proper definition of the insertion function should use a <code><span class='Modifier'>˙</span></code>, like this:</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=bSB78J2VqMuZ4oy+KDLiirjiipEpIPCdlal9IDHigL8y4oC/M+KAvzQ=">↗️</a><pre> <span class='Value'>m</span> <span class='Brace'>{</span><span class='Value'>𝕨</span><span class='Modifier'>˙</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>⊑</span><span class='Paren'>)</span> <span class='Value'>𝕩</span><span class='Brace'>}</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span>
⟨ 1 2 - 4 ⟩
</pre>
diff --git a/docs/doc/group.html b/docs/doc/group.html
index 8184f09f..a79305cc 100644
--- a/docs/doc/group.html
+++ b/docs/doc/group.html
@@ -185,7 +185,7 @@
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=JyAnKCjiiqIty5zCrMOXK2Ap4oiYPeKKlOKKoikiQlFOIHVzZXMgbm90YXRpb24gYXMgYSB0b29sIG9mIHRob3VnaHQi">↗️</a><pre> <span class='String'>' '</span><span class='Paren'>((</span><span class='Function'>⊢-</span><span class='Modifier'>˜</span><span class='Function'>¬×+</span><span class='Modifier'>`</span><span class='Paren'>)</span><span class='Modifier2'>∘</span><span class='Function'>=⊔⊢</span><span class='Paren'>)</span><span class='String'>&quot;BQN uses notation as a tool of thought&quot;</span>
⟨ "BQN" "uses" "notation" "as" "a" "tool" "of" "thought" ⟩
</pre>
-<p>A function with structural Under, such as <code><span class='Brace'>{</span><span class='Number'>¯1</span><span class='Modifier'>¨</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>𝕩</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>, would also work.</p>
+<p>A function with structural <a href="under.html">Under</a>, such as <code><span class='Brace'>{</span><span class='Number'>¯1</span><span class='Modifier'>¨</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Value'>𝕩</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>, would also work.</p>
<p>In other cases, we might want to split on spaces, so that words are separated by any number of spaces, and extra spaces don't affect the output. Currently our function makes a new word with each space:</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=JyAnKCjiiqIty5zCrMOXK2Ap4oiYPeKKlOKKoikiICBzdHJpbmcgd2l0aCAgc3BhY2VzICAgIg==">↗️</a><pre> <span class='String'>' '</span><span class='Paren'>((</span><span class='Function'>⊢-</span><span class='Modifier'>˜</span><span class='Function'>¬×+</span><span class='Modifier'>`</span><span class='Paren'>)</span><span class='Modifier2'>∘</span><span class='Function'>=⊔⊢</span><span class='Paren'>)</span><span class='String'>&quot; string with spaces &quot;</span>
⟨ ⟨⟩ ⟨⟩ "string" "with" ⟨⟩ "spaces" ⟩
diff --git a/docs/doc/identity.html b/docs/doc/identity.html
index 140b79b7..520e1657 100644
--- a/docs/doc/identity.html
+++ b/docs/doc/identity.html
@@ -39,7 +39,7 @@
0 0 0 0 0
</pre>
-<p>A more powerful pattern is with dyadic Under (<code><span class='Modifier2'>⌾</span></code>): unselected parts of the result will use values from <code><span class='Value'>𝕩</span></code>. If <code><span class='Function'>𝔽</span></code> is <code><span class='Function'>⊣</span></code>, then the selected ones will use values from <code><span class='Value'>𝕨</span></code>, merging these arrays together.</p>
+<p>A more powerful pattern is with dyadic <a href="under.html">Under</a> (<code><span class='Modifier2'>⌾</span></code>): unselected parts of the result will use values from <code><span class='Value'>𝕩</span></code>. If <code><span class='Function'>𝔽</span></code> is <code><span class='Function'>⊣</span></code>, then the selected ones will use values from <code><span class='Value'>𝕨</span></code>, merging these arrays together.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=IkFCQ0RFIiDiiqPijL4oMOKAvzHigL8x4oC/MOKAvzDiirgvKSAiYWJjZGUiCgrin6gid3h5IuKAvyJ6IixA4p+pIOKKo+KMvigx4oqR4oqR4oiY4oqRKSDin6jin6jihpUzLOKGlTLin6ksNOKAvzXin6k=">↗️</a><pre> <span class='String'>&quot;ABCDE&quot;</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span> <span class='String'>&quot;abcde&quot;</span>
"aBCde"
diff --git a/docs/doc/index.html b/docs/doc/index.html
index e035cec4..f05f080b 100644
--- a/docs/doc/index.html
+++ b/docs/doc/index.html
@@ -78,6 +78,7 @@
<li><a href="couple.html">Solo, Couple, and Merge: <code><span class='Function'>≍&gt;</span></code></a></li>
<li><a href="take.html">Take and Drop: <code><span class='Function'>↑</span></code></a></li>
<li><a href="transpose.html">Transpose: <code><span class='Function'>⍉</span></code></a></li>
+<li><a href="under.html">Under: <code><span class='Modifier2'>⌾</span></code></a></li>
<li><a href="undo.html">Undo: <code><span class='Modifier'>⁼</span></code></a></li>
<li><a href="valences.html">Valences: <code><span class='Modifier2'>⊘</span></code></a></li>
<li><a href="windows.html">Windows: <code><span class='Function'>↕</span></code></a></li>
diff --git a/docs/doc/primitive.html b/docs/doc/primitive.html
index fd153f5a..84ee299e 100644
--- a/docs/doc/primitive.html
+++ b/docs/doc/primitive.html
@@ -461,7 +461,7 @@
</tr>
<tr>
<td><code><span class='Modifier2'>⌾</span></code></td>
-<td>Under</td>
+<td><a href="under.html">Under</a></td>
<td><code><span class='Brace'>{</span><span class='Function'>𝔾</span><span class='Modifier'>⁼</span><span class='Modifier2'>∘</span><span class='Function'>𝔽</span><span class='Modifier2'>○</span><span class='Function'>𝔾</span><span class='Brace'>}</span></code> OR <code><span class='Brace'>{</span><span class='Paren'>(</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Gets'>↩</span><span class='Value'>𝕨</span><span class='Function'>𝔽</span><span class='Modifier2'>○</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Separator'>⋄</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code></td>
<td>Apply <code><span class='Function'>𝔽</span></code> over <code><span class='Function'>𝔾</span></code>, then undo <code><span class='Function'>𝔾</span></code></td>
</tr>
diff --git a/docs/doc/replicate.html b/docs/doc/replicate.html
index 1b2c461f..31e63228 100644
--- a/docs/doc/replicate.html
+++ b/docs/doc/replicate.html
@@ -86,7 +86,7 @@
</svg>
<p>The functions Indices and Replicate are used to copy or filter data. They might be described as transforming a <a href="https://en.wikipedia.org/wiki/Run-length_encoding">run-length encoding</a> into unencoded form. On the other hand, Indices might be described as giving a sparse representation of <code><span class='Value'>𝕩</span></code>, which is smaller if <code><span class='Value'>𝕩</span></code> mostly consists of zeros.</p>
-<p>BQN doesn't have any of the various features used in APL to add fills to the result of Replicate, like negative numbers in <code><span class='Value'>𝕨</span></code> or an Expand (<code><span class='Value'>\</span></code>) primitive. An alternative to Expand is to use Replicate with structural Under (<code><span class='Modifier2'>⌾</span></code>) to insert values into an array of fills.</p>
+<p>BQN doesn't have any of the various features used in APL to add fills to the result of Replicate, like negative numbers in <code><span class='Value'>𝕨</span></code> or an Expand (<code><span class='Value'>\</span></code>) primitive. An alternative to Expand is to use Replicate with structural <a href="under.html">Under</a> (<code><span class='Modifier2'>⌾</span></code>) to insert values into an array of fills.</p>
<h2 id="replicate"><a class="header" href="#replicate">Replicate</a></h2>
<p>Given a list of natural numbers <code><span class='Value'>𝕨</span></code>, Replicate repeats each major cell in <code><span class='Value'>𝕩</span></code> the corresponding number of times. That is, <code><span class='Value'>𝕨</span></code> and <code><span class='Value'>𝕩</span></code> must have the same length, and the result includes <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>𝕨</span></code> copies of each cell <code><span class='Value'>i</span><span class='Function'>⊏</span><span class='Value'>𝕩</span></code>, in order.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MuKAvzHigL8w4oC/MiAvICJhYmNkIgoK4oqiIGEg4oaQID4iYWEwIuKAvyJiYjEi4oC/ImNjMiLigL8iZGQzIgoKMuKAvzHigL8w4oC/MiAvIGE=">↗️</a><pre> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span> <span class='Function'>/</span> <span class='String'>&quot;abcd&quot;</span>
diff --git a/docs/doc/reshape.html b/docs/doc/reshape.html
index 2dbceced..963d03a3 100644
--- a/docs/doc/reshape.html
+++ b/docs/doc/reshape.html
@@ -206,7 +206,7 @@
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K8K0y5gg4oaR4oC/NCDipYog4p+oMCwyLDEsMSwgNSw5LDYsNCwgMywzLDMsMywgOSw34p+p">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>´˘</span> <span class='Function'>↑</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Function'>⥊</span> <span class='Bracket'>⟨</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span> <span class='Number'>5</span><span class='Separator'>,</span><span class='Number'>9</span><span class='Separator'>,</span><span class='Number'>6</span><span class='Separator'>,</span><span class='Number'>4</span><span class='Separator'>,</span> <span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Separator'>,</span> <span class='Number'>9</span><span class='Separator'>,</span><span class='Number'>7</span><span class='Bracket'>⟩</span>
⟨ 4 24 12 16 ⟩
</pre>
-<p>Computed Reshape can even be used with structural Under. Only the <code><span class='Modifier2'>∘</span></code> case really makes sense, although <code><span class='Function'>⌊</span></code>, which leaves trailing elements unchanged, could conceivably be useful. Below, we split one argument into three groups and <a href="reverse.html">reverse</a> their order, and reverse groups of three in another.</p>
+<p>Computed Reshape can even be used with <a href="under.html#structural-under">structural Under</a>. Only the <code><span class='Modifier2'>∘</span></code> case really makes sense, although <code><span class='Function'>⌊</span></code>, which leaves trailing elements unchanged, could conceivably be useful. Below, we split one argument into three groups and <a href="reverse.html">reverse</a> their order, and reverse groups of three in another.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oy94oy+KDPigL/iiJjiirjipYopIOKGlTE1CgrijL3ijL4o4oiY4oC/M+KKuOKliikgIm5vbHlyaWNzaGVyZSI=">↗️</a><pre> <span class='Function'>⌽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Modifier2'>∘⊸</span><span class='Function'>⥊</span><span class='Paren'>)</span> <span class='Function'>↕</span><span class='Number'>15</span>
⟨ 10 11 12 13 14 5 6 7 8 9 0 1 2 3 4 ⟩
diff --git a/docs/doc/scan.html b/docs/doc/scan.html
index 9d881cba..c975e35c 100644
--- a/docs/doc/scan.html
+++ b/docs/doc/scan.html
@@ -109,7 +109,7 @@
"ab\rs\\"
</pre>
<h2 id="reverse-scan"><a class="header" href="#reverse-scan">Reverse scan</a></h2>
-<p>We've discussed how the scan moves forward along <code><span class='Value'>𝕩</span></code>, so that each time <code><span class='Function'>𝔽</span></code> takes an old result as <code><span class='Value'>𝕨</span></code> and a new value as <code><span class='Value'>𝕩</span></code>. This means that results correspond to <a href="prefixes.html">prefixes</a> and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan Under <a href="reverse.html">Reverse</a> (<code><span class='Modifier'>`</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) does the trick.</p>
+<p>We've discussed how the scan moves forward along <code><span class='Value'>𝕩</span></code>, so that each time <code><span class='Function'>𝔽</span></code> takes an old result as <code><span class='Value'>𝕨</span></code> and a new value as <code><span class='Value'>𝕩</span></code>. This means that results correspond to <a href="prefixes.html">prefixes</a> and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan <a href="under.html">Under</a> <a href="reverse.html">Reverse</a> (<code><span class='Modifier'>`</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) does the trick.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oioYCAgIDDigL8w4oC/MeKAvzDigL8w4oC/MeKAvzAKCuKIqGDijL7ijL0gMOKAvzDigL8x4oC/MOKAvzDigL8x4oC/MA==">↗️</a><pre> <span class='Function'>∨</span><span class='Modifier'>`</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span>
⟨ 0 0 1 1 1 1 1 ⟩
diff --git a/docs/doc/search.html b/docs/doc/search.html
index 28e0081d..2e75dc97 100644
--- a/docs/doc/search.html
+++ b/docs/doc/search.html
@@ -213,7 +213,7 @@
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=c3R1ZmYg4oqR4oiY4oqQ4p+cPCAic3RyaW5nIg==">↗️</a><pre> <span class='Value'>stuff</span> <span class='Function'>⊑</span><span class='Modifier2'>∘</span><span class='Function'>⊐</span><span class='Modifier2'>⟜</span><span class='Function'>&lt;</span> <span class='String'>&quot;string&quot;</span>
2
</pre>
-<p>If <code><span class='Value'>𝕨</span></code> is fixed, then the version I prefer is to use Under to enclose the argument and then un-enclose the result. It requires <code><span class='Value'>𝕨</span></code> to be bound to <code><span class='Function'>⊐</span></code> because otherwise Under would enclose <code><span class='Value'>𝕨</span></code> as well, since it applies <code><span class='Function'>𝔾</span></code> to both arguments.</p>
+<p>If <code><span class='Value'>𝕨</span></code> is fixed, then the version I prefer is to use <a href="under.html">Under</a> to enclose the argument and then un-enclose the result. It requires <code><span class='Value'>𝕨</span></code> to be bound to <code><span class='Function'>⊐</span></code> because otherwise Under would enclose <code><span class='Value'>𝕨</span></code> as well, since it applies <code><span class='Function'>𝔾</span></code> to both arguments.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=c3R1ZmbiirjiipDijL48ICJzdHJpbmci">↗️</a><pre> <span class='Value'>stuff</span><span class='Modifier2'>⊸</span><span class='Function'>⊐</span><span class='Modifier2'>⌾</span><span class='Function'>&lt;</span> <span class='String'>&quot;string&quot;</span>
2
</pre>
diff --git a/docs/doc/selfcmp.html b/docs/doc/selfcmp.html
index 90438b04..e5a8aa84 100644
--- a/docs/doc/selfcmp.html
+++ b/docs/doc/selfcmp.html
@@ -250,7 +250,7 @@
<p>A more efficient way when <code><span class='Function'>⊒</span></code> doesn't have a fast implementation is <code><span class='Function'>/</span><span class='Paren'>(</span><span class='Number'>¯1</span><span class='Modifier2'>⊸</span><span class='Function'>⊑↕</span><span class='Modifier2'>⊸</span><span class='Function'>-⊏</span><span class='Modifier2'>⟜</span><span class='Function'>»</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span></code>, but that's clearly quite a bit more complicated.</p>
<h3 id="deduplicate"><a class="header" href="#deduplicate">Deduplicate</a></h3>
<p><em>There's also an <a href="https://aplwiki.com/wiki/Unique">APL Wiki page</a> on this function.</em></p>
-<p>Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate Under Reverse (<code><span class='Function'>⍷</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) orders by last occurrence instead.</p>
+<p>Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate <a href="under.html">Under</a> Reverse (<code><span class='Function'>⍷</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) orders by last occurrence instead.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4o23ID4idGFrZSLigL8iZHJvcCLigL8iZHJvcCLigL8icGljayLigL8idGFrZSLigL8idGFrZSIKCuKNt+KMvuKMvSA+InRha2Ui4oC/ImRyb3Ai4oC/ImRyb3Ai4oC/InBpY2si4oC/InRha2Ui4oC/InRha2Ui">↗️</a><pre> <span class='Function'>⍷</span> <span class='Function'>&gt;</span><span class='String'>&quot;take&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;drop&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;drop&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;pick&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;take&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;take&quot;</span>
┌─
╵"take
diff --git a/docs/doc/under.html b/docs/doc/under.html
index 240fa324..58c9f9d4 100644
--- a/docs/doc/under.html
+++ b/docs/doc/under.html
@@ -26,3 +26,81 @@
</g>
</svg>
+<p>The Under 2-modifier expresses the idea of modifying <em>part</em> of an array, or applying a function in a different domain, such as working in logarithmic space. It works with a transformation <code><span class='Function'>𝔾</span></code> that applies to the original argument <code><span class='Value'>𝕩</span></code>, and a function <code><span class='Function'>𝔽</span></code> that applies to the result of <code><span class='Function'>𝔾</span></code> (and if <code><span class='Value'>𝕨</span></code> is given, <code><span class='Function'>𝔾</span><span class='Value'>𝕨</span></code> is used as the left argument to <code><span class='Function'>𝔽</span></code>). Under does the &quot;same thing&quot; as <code><span class='Function'>𝔽</span></code>, but to the original argument, by applying <code><span class='Function'>𝔾</span></code>, then <code><span class='Function'>𝔽</span></code>, then undoing <code><span class='Function'>𝔾</span></code> somehow.</p>
+<p>It's not always possible to undo <code><span class='Function'>𝔾</span></code>, so only some right operands will work. BQN supports two cases. <strong>Computational</strong> Under tries the <a href="undo.html">Undo</a> modifier, so that <code><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span></code> is <code><span class='Function'>𝔾</span><span class='Modifier'>⁼</span><span class='Modifier2'>∘</span><span class='Function'>𝔽</span><span class='Modifier2'>○</span><span class='Function'>𝔾</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MyAr4oy+KMOXy5wpIDQgICMgU3F1YXJlIHJvb3Qgb2Ygc3VtIG9mIHNxdWFyZXM=">↗️</a><pre> <span class='Number'>3</span> <span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>×</span><span class='Modifier'>˜</span><span class='Paren'>)</span> <span class='Number'>4</span> <span class='Comment'># Square root of sum of squares
+</span>5
+</pre>
+<p><strong>Structural</strong> Under is used when <code><span class='Function'>𝔾</span></code> selects part of the array. BQN tracks what was selected and puts the results from <code><span class='Function'>𝔽</span></code> back where they came from.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K2DijL7iiL4g4p+oM+KAvzHigL8wLCAy4oC/NSwgMOKAvzDigL824p+pICAjIFByZWZpeCBzdW0sIGtlZXBpbmcgc3RydWN0dXJl">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>`</span><span class='Modifier2'>⌾</span><span class='Function'>∾</span> <span class='Bracket'>⟨</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Separator'>,</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Separator'>,</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Bracket'>⟩</span> <span class='Comment'># Prefix sum, keeping structure
+</span>⟨ ⟨ 3 4 4 ⟩ ⟨ 6 11 ⟩ ⟨ 11 11 17 ⟩ ⟩
+</pre>
+<p>Structural Under is an essential part of BQN because of how it can &quot;change&quot; an immutable <a href="array.html">array</a>, and it supports more functions and is always well defined. Computational Under's nice, but not so important. The reason they can both be supported as a single primitive is that they follow this unifying principle:</p>
+<pre><span class='Paren'>(</span><span class='Function'>𝔾</span> <span class='Value'>𝕨</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Paren'>)</span> <span class='Function'>≡</span> <span class='Value'>𝕨</span><span class='Function'>𝔽</span><span class='Modifier2'>○</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span>
+</pre>
+<p>That is, when you apply <code><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span></code> <em>before</em> applying <code><span class='Function'>𝔾</span></code>, you get the value that comes from applying <code><span class='Function'>𝔽</span></code> <em>after</em> <code><span class='Function'>𝔾</span></code>. The definition of computational under comes from applying <code><span class='Function'>𝔾</span><span class='Modifier'>⁼</span></code> to both sides and cancelling <code><span class='Function'>𝔾</span><span class='Modifier'>⁼</span><span class='Function'>𝔾</span></code>, which solves the constraint but doesn't have to be a unique solution. For structural Under, the reason this works is that <code><span class='Function'>𝔾</span></code> selects out the parts of <code><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span></code> that were placed back in by Under. Other parts are defined to be the same as it was in <code><span class='Value'>𝕩</span></code>, so the result is fully specified.</p>
+<h2 id="structural-under"><a class="header" href="#structural-under">Structural Under</a></h2>
+<p>A <em>structural function</em> is one that moves elements around without performing computation on them. It's okay if it performs computation, but it has to be based on the structure of its argument—shape, and element structure—and not on the values of atoms in it. As an example, the function <code><span class='Function'>⊏</span><span class='Modifier'>˘</span></code> selects the first column of an array.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGEg4oaQIDTigL8z4qWK4oaVMTIKCjHiirjijL3ijL4o4oqPy5gpIGE=">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>a</span> <span class='Gets'>←</span> <span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Function'>⥊↕</span><span class='Number'>12</span>
+┌─
+╵ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+ ┘
+
+ <span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>⊏</span><span class='Modifier'>˘</span><span class='Paren'>)</span> <span class='Value'>a</span>
+┌─
+╵ 3 1 2
+ 6 4 5
+ 9 7 8
+ 0 10 11
+ ┘
+</pre>
+<p>When used with Under, the function <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span></code> applies to the first column, rotating it. The result of <code><span class='Function'>𝔽</span></code> needs to be compatible with the selection function, so Rotate works but trying to remove an element is no good:</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MeKKuOKGk+KMvijiio/LmCkgYQ==">↗️</a><pre> <span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>↓</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>⊏</span><span class='Modifier'>˘</span><span class='Paren'>)</span> <span class='Value'>a</span>
+<span class='Error'>Error: ⁼: Inverse not found</span>
+</pre>
+<p>BQN can detect lots of structural functions when written in <a href="tacit.html">tacit</a> form; see the list of functions <a href="../spec/inferred.html#required-structural-inverses">in the spec</a>. You can also include computations on the shape. For example, here's a function to reverse the first half of a list.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oy94oy+KOKKouKGkcuc4omgw7cyy5kpICJhYmNkZWYi">↗️</a><pre> <span class='Function'>⌽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>⊢↑</span><span class='Modifier'>˜</span><span class='Function'>≠÷</span><span class='Number'>2</span><span class='Modifier'>˙</span><span class='Paren'>)</span> <span class='String'>&quot;abcdef&quot;</span>
+"cbadef"
+</pre>
+<p>Under is useful with <a href="scan.html">scans</a>, as discussed in a section on <a href="scan.html#reverse-scan">reverse scan</a>. In this case, <code><span class='Function'>⌽</span></code> is exactly invertible, so <code><span class='Modifier2'>⌾</span></code> can just as easily be seen as computational Under. When <code><span class='Function'>𝔾</span></code> has an exact inverse, there can only be one solution to the constraint on Under, and both forms must be the same.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oinYOKMvuKMvSAx4oC/MOKAvzHigL8w4oC/MeKAvzHigL8x">↗️</a><pre> <span class='Function'>∧</span><span class='Modifier'>`</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span>
+⟨ 0 0 0 0 1 1 1 ⟩
+</pre>
+<h2 id="computational-under"><a class="header" href="#computational-under">Computational Under</a></h2>
+<p>Computational Under is based on <a href="undo.html">Undo</a> (<code><span class='Modifier'>⁼</span></code>), and applies whenever structural Under doesn't. It's still limited, because Undo doesn't work on many or even most functions. One common use is with the square function <code><span class='Function'>×</span><span class='Modifier'>˜</span></code>, for computations such as finding the magnitude of a vector, or a <a href="https://en.wikipedia.org/wiki/Root_mean_square">root-mean-square</a> average like the one below.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KCvCtMO34omgKeKMvijDl8ucKSAy4oC/M+KAvzTigL81">↗️</a><pre> <span class='Paren'>(</span><span class='Function'>+</span><span class='Modifier'>´</span><span class='Function'>÷≠</span><span class='Paren'>)</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>×</span><span class='Modifier'>˜</span><span class='Paren'>)</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>
+3.674234614174767
+</pre>
+<p>This average is the square root of the average of the squares of the arguments, and <code><span class='Modifier2'>⌾</span></code> lets us combine the two square-y steps. Similarly, <code><span class='Modifier2'>⌾</span><span class='Function'>÷</span></code> can be used for a harmonic sum or mean (you might notice that computational Under is a lot more mathy than the structural one).</p>
+<p>Under is the idiomatic way to do a round-to-nearest function:</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oyK4oy+KDEw4oq4w5cpIDMuNTI04oC/Ni43OTnigL8yLjAzMQ==">↗️</a><pre> <span class='Function'>⌊</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>10</span><span class='Modifier2'>⊸</span><span class='Function'>×</span><span class='Paren'>)</span> <span class='Number'>3.524</span><span class='Ligature'>‿</span><span class='Number'>6.799</span><span class='Ligature'>‿</span><span class='Number'>2.031</span>
+⟨ 3.5 6.7 2 ⟩
+</pre>
+<p>See how it works? <code><span class='Function'>⌊</span></code> rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (single decimals are now integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... &lt;20. If I had the right range <code><span class='Function'>↕</span><span class='Value'>n</span></code>, then it would be <code><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×↕</span><span class='Value'>n</span></code>, or <code><span class='Paren'>(</span><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×⊢</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>n</span></code>. By using the <em>inverse</em> of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oaV4oiY4oyI4oy+KCg0KzPDl+KKoinigbwpIDIw">↗️</a><pre> <span class='Function'>↕</span><span class='Modifier2'>∘</span><span class='Function'>⌈</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×⊢</span><span class='Paren'>)</span><span class='Modifier'>⁼</span><span class='Paren'>)</span> <span class='Number'>20</span>
+⟨ 4 7 10 13 16 19 ⟩
+</pre>
+<p>Well, really it's a bit of simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge.</p>
+<h2 id="left-argument"><a class="header" href="#left-argument">Left argument</a></h2>
+<p>When called dyadically, Under applies <code><span class='Function'>𝔽</span></code> dyadically, like <a href="compose.html#over">Over</a>. This doesn't affect the undoing part of Under, which still tries to put the result of <code><span class='Function'>𝔽</span></code> back into <code><span class='Value'>𝕩</span></code> for structural Under or invert <code><span class='Function'>𝔾</span></code> for computational. In fact, <code><span class='Value'>𝕨</span> <span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code> is equivalent to <code><span class='Paren'>(</span><span class='Function'>𝔾</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Modifier'>˙</span><span class='Modifier2'>⊸</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code> so no exciting language stuff is happening here at all.</p>
+<p>But you can still do some cool stuff with it! One pattern is simply to set <code><span class='Function'>𝔽</span></code> to <code><span class='Function'>⊣</span></code>, the <a href="identity.html">identity</a> function that just returns its left argument. Now structural Under will replace everything that <code><span class='Function'>𝔾</span></code> selects from <code><span class='Value'>𝕩</span></code> with the corresponding values in <code><span class='Value'>𝕨</span></code>. Here's an example that replaces elements with indices <code><span class='Number'>1</span></code> and <code><span class='Number'>2</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ImFiY2QiIOKKo+KMvigx4oC/MuKKuOKKjykgIjAxMjMi">↗️</a><pre> <span class='String'>&quot;abcd&quot;</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>⊏</span><span class='Paren'>)</span> <span class='String'>&quot;0123&quot;</span>
+"0bc3"
+</pre>
+<p>This method can replace deeper structure too. Below, <code><span class='Function'>𝔾</span></code> is <code><span class='Number'>¯1</span><span class='Function'>⊑</span><span class='Modifier'>¨</span><span class='Number'>2</span><span class='Function'>↑⊢</span></code>, selecting the last element of each of the first two elements of its argument. The elements that aren't selected don't have to match up.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4p+oImFiIiwgImNkZSIsICJmZyLin6kg4oqj4oy+KMKvMeKKkcKoMuKGkeKKoikg4oaVwqgz4oC/MuKAvzHigL8x">↗️</a><pre> <span class='Bracket'>⟨</span><span class='String'>&quot;ab&quot;</span><span class='Separator'>,</span> <span class='String'>&quot;cde&quot;</span><span class='Separator'>,</span> <span class='String'>&quot;fg&quot;</span><span class='Bracket'>⟩</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>¯1</span><span class='Function'>⊑</span><span class='Modifier'>¨</span><span class='Number'>2</span><span class='Function'>↑⊢</span><span class='Paren'>)</span> <span class='Function'>↕</span><span class='Modifier'>¨</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span>
+⟨ ⟨ 0 1 'b' ⟩ ⟨ 0 'e' ⟩ ⟨ 0 ⟩ ⟨ 0 ⟩ ⟩
+</pre>
+<p>In fact, the elements that <em>are</em> selected don't really have to match up before being selected. So here's an example with <a href="join.html">Join</a> where the same pattern is used to &quot;re-flow&quot; <code><span class='Value'>𝕨</span></code> into the structure of <code><span class='Value'>𝕩</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4p+oImFiIiwgImNkZSIsICJmZyLin6kg4oqj4oy+4oi+IOKfqCItLS0iLCAiLS0tLSLin6k=">↗️</a><pre> <span class='Bracket'>⟨</span><span class='String'>&quot;ab&quot;</span><span class='Separator'>,</span> <span class='String'>&quot;cde&quot;</span><span class='Separator'>,</span> <span class='String'>&quot;fg&quot;</span><span class='Bracket'>⟩</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Function'>∾</span> <span class='Bracket'>⟨</span><span class='String'>&quot;---&quot;</span><span class='Separator'>,</span> <span class='String'>&quot;----&quot;</span><span class='Bracket'>⟩</span>
+⟨ "abc" "defg" ⟩
+</pre>
+<h3 id="and-getting-it-not-to-do-that"><a class="header" href="#and-getting-it-not-to-do-that">And getting it not to do that</a></h3>
+<p>The Over-based action on <code><span class='Value'>𝕨</span></code> shows up more than you might think, but sometimes you just want to pass a left argument to <code><span class='Function'>𝔽</span></code> without <code><span class='Function'>𝔾</span></code> getting involved. In this case you have to <a href="hook.html#bind">bind</a> it in: call <code><span class='Value'>𝕨</span><span class='Modifier2'>⊸</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MeKAvzLigL8z4oq4K+KMvigx4oC/MeKAvzDigL8x4oq4LykgMTDigL8yMOKAvzMw4oC/NDA=">↗️</a><pre> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span> <span class='Number'>10</span><span class='Ligature'>‿</span><span class='Number'>20</span><span class='Ligature'>‿</span><span class='Number'>30</span><span class='Ligature'>‿</span><span class='Number'>40</span>
+⟨ 11 22 30 43 ⟩
+</pre>
+<p>This <a href="../problems.html#underbind-combination-is-awkward">gets bad</a> when you want <code><span class='Value'>𝕨</span></code> to be an argument. In the worst case you might need to write out an operator <code><span class='Brace'>{</span><span class='Value'>𝕨</span><span class='Modifier2'>⊸</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code>.</p>
diff --git a/docs/doc/undo.html b/docs/doc/undo.html
index 3a2ddcba..daf1b60d 100644
--- a/docs/doc/undo.html
+++ b/docs/doc/undo.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="undo"><a class="header" href="#undo">Undo</a></h1>
-<p>Oh no, you've deleted a function after spending half an hour writing it! Well… hopefully your editor can help with that. But maybe you'll be interested to hear that BQN can reverse the action of some functions—ones that <em>don't</em> lose information. This capability is also used by <a href="repeat.html">Repeat</a> (<code><span class='Modifier2'>⍟</span></code>) to repeat a negative number of times.</p>
+<p>Oh no, you've deleted a function after spending half an hour writing it! Well… hopefully your editor can help with that. But maybe you'll be interested to hear that BQN can reverse the action of some functions—ones that <em>don't</em> lose information. This capability is also used by <a href="repeat.html">Repeat</a> (<code><span class='Modifier2'>⍟</span></code>) to repeat a negative number of times, and <a href="under.html">Under</a> (<code><span class='Modifier2'>⌾</span></code>) in some cases.</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MiDijL0gImFiY2RlIgoKMiDijL3igbwgMiDijL0gImFiY2RlIg==">↗️</a><pre> <span class='Number'>2</span> <span class='Function'>⌽</span> <span class='String'>&quot;abcde&quot;</span>
"cdeab"
@@ -19,7 +19,7 @@
<span class='Function'>Fn</span><span class='Modifier'>⁼</span> <span class='Function'>Fn</span> <span class='String'>&quot;BQN&quot;</span>
"BQN"
</pre>
-<p>Here it undoes a function to decrement the last character by incrementing that character. In part this is enabled by the clean design of BQN primitives, because better-behaved functions like those using structural Under are easier to invert.</p>
+<p>Here it undoes a function to decrement the last character by incrementing that character. In part this is enabled by the clean design of BQN primitives, because better-behaved functions like those using structural <a href="under.html">Under</a> are easier to invert.</p>
<h2 id="the-rules"><a class="header" href="#the-rules">The rules</a></h2>
<p>If <code><span class='Function'>𝔽</span></code> can be inverted exactly, then Undo just does that. However, there are also some other functions that BQN inverts. For example, the squaring function <code><span class='Function'>×</span><span class='Modifier'>˜</span></code> has both a positive and a negative inverse, and yet:</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=w5fLnCDCrzMKw5fLnOKBvCDDl8ucIMKvMyAgIyBJdCdzIG5vdCB0aGUgc2FtZSE=">↗️</a><pre> <span class='Function'>×</span><span class='Modifier'>˜</span> <span class='Number'>¯3</span>
diff --git a/docs/help/under.html b/docs/help/under.html
index c55d48b2..9f70d005 100644
--- a/docs/help/under.html
+++ b/docs/help/under.html
@@ -6,6 +6,7 @@
<div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">help</a></div>
<h1 id="circle-jot-"><a class="header" href="#circle-jot-">Circle Jot (<code><span class='Modifier2'>⌾</span></code>)</a></h1>
<h2 id="𝔽𝔾-𝕩-𝕨-𝔽𝔾-𝕩-under"><a class="header" href="#𝔽𝔾-𝕩-𝕨-𝔽𝔾-𝕩-under"><code><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code>, <code><span class='Value'>𝕨</span> <span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code>: Under</a></h2>
+<p><a class="fulldoc" href="../doc/under.html">→full documentation</a></p>
<ul>
<li>Apply transformation <code><span class='Function'>𝔾</span></code> to all arguments</li>
<li>Apply <code><span class='Function'>𝔽</span></code> to the transformed arguments</li>
diff --git a/help/under.md b/help/under.md
index b15fa115..72f61e8f 100644
--- a/help/under.md
+++ b/help/under.md
@@ -3,6 +3,7 @@
# Circle Jot (`⌾`)
## `𝔽⌾𝔾 𝕩`, `𝕨 𝔽⌾𝔾 𝕩`: Under
+[→full documentation](../doc/under.md)
- Apply transformation `𝔾` to all arguments
- Apply `𝔽` to the transformed arguments