aboutsummaryrefslogtreecommitdiff
path: root/rprt.md
diff options
context:
space:
mode:
Diffstat (limited to 'rprt.md')
-rw-r--r--rprt.md204
1 files changed, 166 insertions, 38 deletions
diff --git a/rprt.md b/rprt.md
index 2b06cc4..5bcbec5 100644
--- a/rprt.md
+++ b/rprt.md
@@ -13,7 +13,7 @@ All functions work with two core types:
Every selection exists within one or more buffers. Selections have a rank:
- **Rank 0**: Position — a natural number offset within a single buffer
- - **Rank 1**: Range — a pair of positions [start,end) with capture groups, within a single buffer
+ - **Rank 1**: Range — a pair of positions `[start, end)` with capture groups, within a single buffer
- **Rank 2**: Ranges — a list of ranges with capture groups, within a single buffer
- **Rank 3**: Multi-buffer selection — a mapping from buffer identifiers to rank 2 selections
@@ -29,17 +29,78 @@ A **Text function** is something of signature `Selection × Text → Selection`.
Following APL conventions, functions may have nullary, monadic, and dyadic forms. In these cases the number of arguments that they take varies (though not their types).
-### [Leading axis theory](https://aplwiki.com/wiki/Leading_axis_theory) and broadcasting
+### Type Coercion
-The leading axis is the buffer selection, followed by the range _index_, followed by the character position in each range. When broadcasting occurs axes are aligned.
+When a Text argument is required, a Selection is implicitly coerced to Text by extracting its contents. This coercion has no side effects.
+
+| Input rank | Coerced Text |
+|------------|---------------------------------------------------|
+| 0 | Empty string (position has no extent) |
+| 1 | Contents of the range |
+| 2 | Contents of each range (multiple text values) |
+| 3 | Contents per buffer per range (multiple values) |
+
+For ranks 2 and 3, the selection provides multiple text values. Text functions pair these values with selection ranges following the broadcasting rules in §1.2.
+
+**Text constants as functions:** A Text constant (string literal) `"text"` can be used as a constant nullary or monadic Text function that always returns `"text"`, ignoring its argument. This allows Text constants to be composed with other functions using combinators like hooks and trains.
+
+## 1.2 Notation, [Leading axis theory](https://aplwiki.com/wiki/Leading_axis_theory), and broadcasting
+
+**Notation:** In dyadic function application `α F ω`, `α` (alpha) is the left argument, `F` is the function, and `ω` (omega) is the right argument. For Selection functions `ω` may be omitted to obtain the monadic form `α F` of `F`. For Text functions `α` may be omitted to obtain the monadic form `F ω` of `F`.
+
+Selections have a hierarchical structure with two axes, ordered from outermost (leading) to innermost:
+
+1. **Buffer axis**: Distinct buffer identifiers (rank 3 only)
+2. **Range axis**: Range index within list of ranges (ranks 2-3)
-TODO `α F ω` explain
+Selection functions define distinct **rank 0** and **rank 1** semantics. Higher rank selections are processed by **vectorisation**: the rank 1 semantics are applied to each range.
+
+**Monadic rank polymorphism** for `α F`:
+
+| `α` rank | Semantics |
+|----------|-----------------------------------------------------------------------------------------------|
+| 0 | Apply rank 0 semantics of `F` |
+| 1 | Apply rank 1 semantics of `F` |
+| 2 | Vectorise: collect `α' F` into ranges, where `α'` varies over each range in `α` |
+| 3 | Vectorise: collect `α' F` per buffer, where `α'` varies over the ranges in each buffer of `α` |
+
+**Dyadic selection functions:** The span function `-` (§2.1) is the only dyadic selection function. It broadcasts its rank 0 and rank 1 semantics across higher ranks following the table above. See §2.1 for the complete broadcasting table.
+
+**Text functions:** Text functions `α F τ` (§3) broadcast along the selection's axes when `α` has rank 2+. If the text argument `τ` is itself a Selection that coerces (§1.1) to multiple text values (rank 2+), the text values are paired with the ranges in `α`.
+
+The buffer axis (rank 3) is the **leading axis**: operations on rank 3 selections distribute per-buffer first, then per-range within each buffer.
### Trains
-TODO
+A **train** is a sequence of functions that compose according to specific rules, following [APL train syntax](https://aplwiki.com/wiki/Train).
+
+**2-train (Atop)** `F G`:
+- Monadic: `(F G) ω = F (G ω)`
+- Dyadic: `α (F G) ω = F (α G ω)`
+
+**3-train (Fork)** `F G H`:
+- Monadic: `(F G H) ω = (F ω) G (H ω)`
+- Dyadic: `α (F G H) ω = (α F ω) G (α H ω)`
-## 1.2 The Editor State Monad
+**Longer trains**: Parsed right-associatively. A train of n functions is parsed by taking the rightmost 3 functions as a fork (if n is odd and ≥3) or the rightmost 2 functions as atop (if n is even), then recursively parsing the remaining functions as the left part. For example:
+- 4 functions `F G H I` → `F (G H I)` (atop of F with a fork)
+- 5 functions `F G H I J` → `(F G) (H I J)` (atop of an atop with a fork)
+
+### Hooks
+
+RPRT provides two explicit hook combinators from BQN for flexible function composition:
+
+**Before (Left Hook)** `F>G`:
+- Monadic: `(F>G) ω = (F ω) G ω`
+- Dyadic: `α (F>G) ω = (F α) G ω`
+
+**After (Right Hook)** `F<G`:
+- Monadic: `(F<G) ω = ω F (G ω)`
+- Dyadic: `α (F<G) ω = α F (G ω)`
+
+These combinators bind more tightly than trains and enable partial application patterns.
+
+## 1.3 The Editor State Monad
All RPRT expressions evaluate within an implicit `EditorState` monad containing:
- Buffer contents (for all open buffers)
@@ -49,20 +110,7 @@ All RPRT expressions evaluate within an implicit `EditorState` monad containing:
Selection and Text functions have signatures `EditorState Selection` and `EditorState Text` respectively.
-## 1.3 Type Coercion
-
-When a Text argument is required, a Selection is implicitly coerced to Text by extracting its contents. This coercion has no side effects.
-
-| Input rank | Coerced Text |
-|------------|------------------------------------------------------------------|
-| 0 | Empty string (position has no extent) |
-| 1 | Contents of the range |
-| 2 | Contents of each range (text function broadcasts per range) |
-| 3 | Contents per buffer per range (broadcasts per buffer then range) |
-
-For ranks 2 and 3, the selection provides multiple text values.
-
-## 1.4 Evaluation Contexts
+## 1.5 Evaluation Contexts
**Top-level Selection:** Sets the editor's current selection.
```
@@ -83,7 +131,7 @@ b "name" # Switch current buffer to "name"
The `b` statement is not a function and cannot be composed. It only appears as a top-level statement.
-## 1.5 The Grouping Operator `{}`
+## 1.6 The Grouping Operator `{}`
The grouping operator `{}` provides transactional semantics: all operations within see the same input editor state, and their modifications are merged with position tracking where possible. Any error aborts the entire evaluation.
@@ -94,7 +142,7 @@ The grouping operator `{}` provides transactional semantics: all operations with
- All operations execute with the original positions
- Returns the union of all resulting Selections
-# 1.6 Composition and Parsing
+# 1.7 Composition and Parsing
**Precedence:** Following BQN rules:
- Operators bind tighter than functions
@@ -122,7 +170,7 @@ There are ten core selection functions in RPRT. All ten have nullary and monadic
| `B/re/` | All buffers whose name match re, mapping to their contents | 3 |
| `-` | Entire buffer (0-$) | 2 |
-In the monadic case, all defined functions are rank preserving. Their action on ranks > 1 are given by broadcasting, that is, `α F` where `α` has rank 2 is computed by applying `F` to each rank 1 range in `α` and collecting the results into a list of ranges, mutatis mutandis for rank 3.
+In the monadic case, functions have distinct rank 0 and rank 1 semantics. For ranks 2-3, the rank 1 semantics vectorise across ranges (see §1.2 for broadcasting and vectorisation).
| Function | Semantics for rank 0 `α` | Semantics for rank 1 `α` |
|-----------|----------------------------------|------------------------------------------|
@@ -154,9 +202,33 @@ The span function `-` is the only selection function with dyadic semantics. It c
## 2.2 Selection Function Operators
-Operators take functions as arguments and return new functions.
+Operators take functions as arguments and return new functions. Selection function operators fall into two categories which compose in a restricted manner:
-### 2.2.1 The Reverse Operator `'`
+**Search Modifiers** (at most one allowed):
+- _(none)_ — Unmodified search semantics (see §2.1)
+- `'` — Reverse (§2.2.2)
+- `;` — Sequential (§2.2.3)
+- `';` — Reverse-Sequential
+- `;'` — Sequential-Reverse
+
+**Result Transformations** (at most one allowed):
+- _(none)_ — Unmodified result
+- `~` — Complement (§2.2.4)
+- `?` — Conditional (§2.2.5)
+- `~?` — Complement-Conditional
+- `?~` — Conditional-Complement
+
+A fully-specified selection function has the form:
+
+```
+[result transformation] [search modifier] [base function]
+```
+
+where both operators are optional. Order matters: `';F` is not `;'F` and `~?F` is not `?~F`.
+
+### 2.2.1 Search modifiers
+
+#### The Reverse Operator `'`
The reverse operator `'` takes a selection function and reverses its direction.
@@ -172,7 +244,7 @@ The reverse operator `'` takes a selection function and reverses its direction.
| `'x/re/` | All matches, right-to-left | 2 |
| `'+n` | Line -n in buffer | 1 |
-In the monadic case, all functions are rank preserving, and all of the above functions are the identity on rank 0 inputs. Their action on ranks > 1 is by broadcasting.
+In the monadic case, all functions are rank preserving, and all of the above functions are the identity on rank 0 inputs. For ranks 2-3, the rank 1 semantics vectorise (see §1.2).
| Function | Semantics for rank 0 `α` | Semantics for rank 1 `α` |
|------------|--------------------------|----------------------------------|
@@ -185,7 +257,7 @@ In the monadic case, all functions are rank preserving, and all of the above fun
| `α '+n` | `α` | Line -n within `α` |
-### 2.2.2 The Sequential Operator `;`
+#### The Sequential Operator `;`
The sequential operator `;` transforms a selection function from operating "within" a selection to operating "starting from the end" of that selection.
@@ -203,7 +275,23 @@ The sequential operator `;` transforms a selection function from operating "with
| `α ;x/re/` | All matches forward from `α` | All matches forward from end of `α` |
| `α ;+n` | Line n after `α` | Line n after end of `α` |
-### 2.2.3 The Complement Operator `~`
+#### Combined Search Modifiers
+
+The reverse and sequential operators may be composed in either order, producing distinct semantics:
+
+**`;'F` (Sequential-Reverse):**
+- Start from the end boundary of the selection
+- Search backward (in reverse direction)
+
+**`';F` (Reverse-Sequential):**
+- Start from the start boundary of the selection
+- Search backward (in reverse direction)
+
+The key distinction is the starting position: `;'F` begins at the end and searches backward, while `';F` begins at the start and searches backward.
+
+### 2.2.2 Result transformations
+
+#### The Complement Operator `~`
The complement operator `~` takes a selection function and produces a new selection function which returns the complement. Naturally this changes rank somewhat, as explained in the below table.
@@ -214,13 +302,39 @@ The complement operator `~` takes a selection function and produces a new select
| 2 | 2 | The selection corresponding to the ranges between the selections |
| 3 | 3 | The broadcast of `~` to each buffer |
+#### The Conditional Operator `?`
+
+The conditional operator `?` takes a selection function and produces a new selection function with the following semantics.
+
+| Expression | Semantics |
+|-----------------|--------------------------------------------------|
+| Nullary `?F` | exactly as `F` |
+| Monadic `α ?F` | if `α F` is non-empty then `α` otherwise empty |
+| Dyadic `α ?F β` | if `α F β` is non-empty then `α` otherwise empty |
+
+#### Combined Result Transformations
+
+The complement and conditional operators may be composed in either order, producing distinct semantics:
+
+**`~?F` (Complement-Conditional):**
+1. Evaluate function `F` to obtain result `α`
+2. Apply conditional: if `α` is non-empty, return input selection; otherwise return empty
+3. Apply complement to the conditional result
+
+**`?~F` (Conditional-Complement):**
+1. Evaluate function `F` to obtain result `α`
+2. Apply complement to `α` to obtain `β`
+3. Apply conditional to `β`
+
+The key distinction is when the complement is applied: `~?F` complements the conditional result, while `?~F` applies conditional to the complemented result of `F`.
+
# 3. Text Functions
## 3.1 Text Operations
Text operations have signature `Selection × Text → Selection`. They modify the editor state (buffer contents) and return the affected Selection.
-Text operations use [leading axis theory](https://aplwiki.com/wiki/Leading_axis_theory) where buffer names are the leading axis: TODO TODO TODO if `α F β` where `β` is rank 2 but `α` is rank 1, then operation applies once per range in `β`, using the contents of each range as the text argument.
+Text operations follow the broadcasting rules described in §1.2. When the text argument `τ` is itself a Selection that coerces to Text, the text values are paired with ranges following the buffer-first, then range-within-buffer ordering (the leading axis).
| Function | Effect | Return selection |
|----------|--------------------------------------------------------------|----------------------|
@@ -259,21 +373,35 @@ Text operations use [leading axis theory](https://aplwiki.com/wiki/Leading_axis_
**Examples:**
-TODO: throw some combinators in to make this example nicer.
-
```
-| "date" # Run date with no input, returns selection to output
-/pattern/ c (| "date") # Replace pattern with date command output
-selection c (selection | "sort") # Pipe selection through sort, replace with result
+| "date" # Run date with no input, returns selection to output
+/pattern/ c (| "date") # Replace pattern with date command output
+α c<(|<"sort") # Pipe selection through sort, replace with result (using After hooks)
```
-An idiom
+The third example composes two After hooks (§1.2): `|<"sort"` creates a monadic selection function that pipes its argument through sort, where `"sort"` is treated as a constant Text function (§1.1). Then `α c<(|<"sort")` expands to `α c (α | "sort")`, avoiding explicit repetition of the selection. Note the parentheses are necessary: `c<|<"sort"` would incorrectly parse as `α c (| "sort")`, running sort with no input.
+
+## 3.2 Text Function Operators
+
+Text function operators modify the behavior of text functions.
+
+### The Swap Operator
+
+The `swap` operator reverses the arguments of a text function, converting `α F τ` into `τ F α`. For this to typecheck both arguments must be selections.
+
+**Syntax:** `@ F`
+
+**Semantics:** `α (@ F) τ = τ F α`
+
+This is particularly useful for composing text operations where the natural argument order needs to be reversed.
+
+**Idiom for moving content:**
```
-α {swap i , d} β
+α {@i , d} β
```
-Evaluates in parallel
-* `α (swap i) β` which is `β i α` which means "insert at (the start of) β the content from α"
+Using the swap operator `@`, this evaluates in parallel:
+* `α @i β` which is `β i α` which means "insert at (the start of) β the content from α"
* `α d β` which means "delete α"
The net result of this is to _move_ the content of α to (the start of) the selection given by β.