# Rank PolymoRphic Text editor (RPRT) A compositional, point-free language for text manipulation. # 1. Core Concepts ## 1.1 Two Fundamental Types All functions work with two core types: 1. **Selection** — addresses and regions in buffers 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 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 Ranks 0-2 operate within a single buffer (typically the current buffer). Rank 3 is distinguished by spanning multiple buffers simultaneously. 2. **Text** — string data ### Function Types A **Selection function** is something of signature `Selection × Selection → Selection`. 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). ### 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 (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) 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 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`: - Niladic: `F G` = (F) G`; `F` is evaluated niladically and `G` is evaluated monadically on the result - Monadic: `ω (F G) = (ω F) G` - Dyadic: `ω (F G) α = (ω F α) G` **3-train (Fork)** `F G H`: - Niladic: `F G H` = `(F) G (H)`; `F`, `H` are evaluated niladically and `G` is evaluated dyadically on the result - Monadic: `ω (F G H) = (ω F) G (ω H)` - Dyadic: `ω (F G H) α = (ω F α) G (ω H α)` **Longer trains**: Parsed left-associatively. A train of n functions is parsed by taking the leftmost 3 functions as a fork (if n is odd and ≥3) or the leftmost 2 functions as atop (if n is even), then recursively parsing the remaining functions as the right part. For example: - 4 functions `F G H I` → `(F G H) I` (I atop a fork) - 5 functions `F G H I J` → `(F G H) (I J)` (atop, atop a fork) ### Hooks RPRT provides two explicit hook combinators from BQN for flexible function composition: **Before (Left Hook)** `F>G`: - Niladic: `F>G = (F) G`; `F` is evaluated niladically and `G` is evaluated monadically on the result - Monadic: `ω (F>G) = (ω F) G ω` - Dyadic: `ω (F>G) α = (ω F) G α` **After (Right Hook)** `F/re/` In the niladic form this is `(.) /re/` (left hook semantics, §1.2), and `.` niladically is the current selection (§3.1). Thus `.>/re/` applies `/re/` to the current selection. The After hook `F