<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>What Comes to Mind (Posts about draft)</title><link>https://sdowney.org/</link><description></description><atom:link href="https://sdowney.org/categories/draft.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:sdowney@sdowney.dev"&gt;Steve Downey&lt;/a&gt; 
 &lt;a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/"&gt;
 &lt;img alt="Creative Commons License BY-NC-SA"
 style="border-width:0; margin-bottom:12px;"
 src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Sun, 27 Sep 2026 18:57:07 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Trees and Transposition</title><link>https://sdowney.org/posts/trees-and-transposition/</link><dc:creator>Steve Downey</dc:creator><description>&lt;div id="ox-nikola-outline-container-orgd615dbf" class="ox-nikola-outline-2"&gt;
&lt;h2 id="orgd615dbf"&gt;&lt;span class="section-number-2"&gt;1.&lt;/span&gt; Abstract&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-1"&gt;
&lt;p&gt;
You have a &lt;code&gt;vector&amp;lt;sender&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt; and you need a &lt;code&gt;sender&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt;, or a &lt;code&gt;vector&amp;lt;optional&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt; and you need an &lt;code&gt;optional&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
You don't want to write a binary tree. Again. By hand.
&lt;/p&gt;

&lt;p&gt;
You have a pure function. You have arguments in two vectors. You just want to zip the arguments together and apply it.
&lt;/p&gt;

&lt;p&gt;
You want to keep working on a data structure while something else works on it. Making copies is expensive.
&lt;/p&gt;

&lt;p&gt;
I am on a campaign to improve support in C++ for contemporary algorithms.
By contemporary I mean more recent than the Sedgewick C++ Algorithms  book I used back in the 90s.
There has been extraordinary work done in programming language and algorithmic research in the last 30 years.
Much of it even well understood and codified enough to be standardized.
&lt;/p&gt;

&lt;p&gt;
It's not one huge paper, though a couple are shaping up to be beefy.
All of them have hooks for the types you already have; none of them asks you to throw away the binary tree you already wrote.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-orgb8d0d3e" class="ox-nikola-outline-2"&gt;
&lt;h2 id="orgb8d0d3e"&gt;&lt;span class="section-number-2"&gt;2.&lt;/span&gt; Why four papers&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-2"&gt;
&lt;p&gt;
This started as a fingertree. A container, adapters for the classic structures it can model, and a Rope.
The algorithms we already have work with it, but only as a Sequence, and a fingertree is a tree.
So it needed algorithms that did not exist yet, and those algorithms have nothing to do with fingertrees.
That is the first paper boundary.
&lt;/p&gt;

&lt;p&gt;
It was always a little strange that the standard library has nothing tree shaped except &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt;.
Trees are basic.
When I looked, it turned out the &lt;code&gt;Fix&lt;/code&gt; data type could be implemented in C++, literally, and it worked surprisingly well.
Pattern matching and the visitor are the same thing at the core, Church encoded sum types fall out of that, and Kmett's recursion schemes stop being exotic.
That is the tree paper, and it has its own reason to exist.
&lt;/p&gt;

&lt;p&gt;
If you have trees, you want to traverse them.
The insight was that &lt;code&gt;invoke&lt;/code&gt; is the key operation and &lt;code&gt;ap&lt;/code&gt; is implementation detail.
That is what P3200 owns, and the tree paper wanted it before I knew what it was.
And then zip lists, data parallelism, and SIMD fell out of the same research, which I had not known going in.
So the base paper is broader than trees.
That is why it is the base.
&lt;/p&gt;

&lt;p&gt;
The papers are in the reverse of the order I found them.
Each one is what the one before it turned out to need, and the last one turned out to be bigger than the need.
&lt;/p&gt;

&lt;p&gt;
They come apart cleanly.
Without traverse and transpose the tree algorithms are less rich, but they are separable and useful: &lt;code&gt;Fix&lt;/code&gt;, the recursion schemes, adaptable to the tree types you already have, treatable as Ranges.
Fingertree survives on its own as a concrete container that most other languages have had for years; the base tree algorithms and the adapters are what make it a rich one.
&lt;/p&gt;

&lt;p&gt;
If only P3200 Transpose survives, we have applicative and traversable, instances for Ranges, and others, and a worked out path for monad.
Range of Context to Context of Ranges is enough.
&lt;/p&gt;

&lt;p&gt;
The word that crosses every boundary is Monoid.
It was one of the first typeclasses I wrote, years ago, trying to get what C++11 concept maps would have given us.
The interface is trivial.
The number of different ways an &lt;code&gt;int&lt;/code&gt; can be a Monoid is what forced most of the decisions about how instances are found and passed around.
&lt;/p&gt;

&lt;p&gt;
Backtick is parallel evolution.
I have been thinking about it since C added &lt;code&gt;`&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, and &lt;code&gt;$&lt;/code&gt; to the basic character set for C23, and about the uniform function call proposals as really being about infix position.
That it was actually possible I did not work out until the Brno WG21 meeting in Spring 2026.
There was also a faction that wanted the backtick for escaping keywords into identifiers.
Both turned out to be possible, but probably only if they were done at once.
The crossover with the rest of this is just that infix is easier to read than nesting, even more than pipelines are.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org96cb16e" class="ox-nikola-outline-2"&gt;
&lt;h2 id="org96cb16e"&gt;&lt;span class="section-number-2"&gt;3.&lt;/span&gt; What?&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-3"&gt;
&lt;p&gt;
The base paper is P3200.
I got the number by honest accident and sat on it.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org1b1f5d9" class="ox-nikola-outline-3"&gt;
&lt;h3 id="org1b1f5d9"&gt;&lt;span class="section-number-3"&gt;3.1.&lt;/span&gt; Transpose&lt;/h3&gt;
&lt;div class="outline-text-3" id="text-3-1"&gt;
&lt;p&gt;
You have a &lt;code&gt;vector&amp;lt;sender&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt; and you need a &lt;code&gt;sender&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt;. Or you need to swap array of struct to struct of array for lane-wise SIMD processing. And you don't want to write that loop one more time.
&lt;/p&gt;

&lt;p&gt;
This is actually what McBride and Paterson invented Applicative and Transpose &lt;b&gt;for&lt;/b&gt;.
Transposing a matrix is the opening example of &lt;a href="https://www.staff.city.ac.uk/~ross/papers/Applicative.html"&gt;&lt;i&gt;Applicative Programming with Effects&lt;/i&gt;&lt;/a&gt; (JFP 2008).
&lt;/p&gt;

&lt;p&gt;
Also, Applicative has almost nothing to do with partial application or currying.
It is all about applying a pure function to arguments in contexts.
&lt;/p&gt;

&lt;p&gt;
One verb, three contexts.
The code is from the &lt;a href="https://github.com/steve-downey/transpose"&gt;transpose&lt;/a&gt; repository's example, which builds and runs in CI.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Every position present: the vector of maybes becomes maybe-a-vector.
&lt;/span&gt;    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;complete&lt;/span&gt;{1, 2, 3};
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;all&lt;/span&gt; = &lt;span class="org-constant"&gt;bt&lt;/span&gt;::transpose(complete);
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"complete input:  has_value = "&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::boolalpha
              &amp;lt;&amp;lt; all.has_value() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;

    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;One gap anywhere and the whole result is empty -- the absence is
&lt;/span&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;hoisted out of the structure, not left inside it.
&lt;/span&gt;    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;gapped&lt;/span&gt;{1, &lt;span class="org-constant"&gt;std&lt;/span&gt;::nullopt, 3};
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;none&lt;/span&gt; = &lt;span class="org-constant"&gt;bt&lt;/span&gt;::transpose(gapped);
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"gapped input:    has_value = "&lt;/span&gt; &amp;lt;&amp;lt; none.has_value() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Each sender defers a computation; running one announces itself.
&lt;/span&gt;    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;deferred&lt;/span&gt; = [](&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;value&lt;/span&gt;) {
        &lt;span class="org-keyword"&gt;return&lt;/span&gt; &lt;span class="org-constant"&gt;bt&lt;/span&gt;::&lt;span class="org-type"&gt;sender&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;{[&lt;span class="org-constant"&gt;value&lt;/span&gt;] {
            &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"  running the sender for "&lt;/span&gt; &amp;lt;&amp;lt; value &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;
            &lt;span class="org-keyword"&gt;return&lt;/span&gt; value * value;
        }};
    };
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;bt&lt;/span&gt;::&lt;span class="org-type"&gt;sender&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;senders&lt;/span&gt;{deferred(1), deferred(2), deferred(3)};

    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;composed&lt;/span&gt; = &lt;span class="org-constant"&gt;bt&lt;/span&gt;::transpose(senders);
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"composed vector&amp;lt;sender&amp;lt;int&amp;gt;&amp;gt; into sender&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;; "&lt;/span&gt;
                 &lt;span class="org-string"&gt;"nothing has run yet\n"&lt;/span&gt;;

    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;values&lt;/span&gt; = composed.get();
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"after get():\n"&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;    &lt;span class="org-keyword"&gt;constexpr&lt;/span&gt; &lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;W&lt;/span&gt; = 4;
    &lt;span class="org-keyword"&gt;using&lt;/span&gt; &lt;span class="org-type"&gt;vec4&lt;/span&gt; = &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-constant"&gt;simd&lt;/span&gt;::&lt;span class="org-type"&gt;vec&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;, W&amp;gt;;

    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Three W-wide computations, one per structure position, filled from
&lt;/span&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;real std::simd arithmetic.
&lt;/span&gt;    &lt;span class="org-type"&gt;vec4&lt;/span&gt; &lt;span class="org-type"&gt;a&lt;/span&gt;([](&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;lane&lt;/span&gt;) { &lt;span class="org-keyword"&gt;return&lt;/span&gt; lane + 1; });        &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;{1, 2, 3, 4}
&lt;/span&gt;    &lt;span class="org-type"&gt;vec4&lt;/span&gt; &lt;span class="org-type"&gt;b&lt;/span&gt;([](&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;lane&lt;/span&gt;) { &lt;span class="org-keyword"&gt;return&lt;/span&gt; (lane + 1) * 10; }); &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;{10, 20, 30, 40}
&lt;/span&gt;    &lt;span class="org-type"&gt;vec4&lt;/span&gt; &lt;span class="org-type"&gt;c&lt;/span&gt;([](&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;lane&lt;/span&gt;) { &lt;span class="org-keyword"&gt;return&lt;/span&gt; (lane + 1) * 100; });

    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;vector&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;bt&lt;/span&gt;::&lt;span class="org-type"&gt;simd_lanes&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;, W&amp;gt;&amp;gt; &lt;span class="org-variable-name"&gt;structure&lt;/span&gt;(3);
    &lt;span class="org-keyword"&gt;for&lt;/span&gt; (&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;lane&lt;/span&gt; = 0; lane &amp;lt; W; ++lane) {
        structure[0].data[lane] = a[lane];
        structure[1].data[lane] = b[lane];
        structure[2].data[lane] = c[lane];
    }

    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;vector&amp;lt;simd_lanes&amp;lt;int, W&amp;gt;&amp;gt; -&amp;gt; simd_lanes&amp;lt;vector&amp;lt;int&amp;gt;, W&amp;gt;: W complete
&lt;/span&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;result vectors, one per hardware lane.
&lt;/span&gt;    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;transposed&lt;/span&gt; = &lt;span class="org-constant"&gt;bt&lt;/span&gt;::transpose(structure);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
P3200, &lt;i&gt;Shape-Preserving Traversal and Transposition for Contextual Computations&lt;/i&gt;, proposes a shape-preserving traversal facility together with &lt;code&gt;transpose&lt;/code&gt; operations that convert a structure of contextual values into a contextual structure, and the bundled customization model it takes to do that coherently.
&lt;/p&gt;

&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/transpose"&gt;https://github.com/steve-downey/transpose&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Transpose Context and Structure&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org514a8fc" class="ox-nikola-outline-3"&gt;
&lt;h3 id="org514a8fc"&gt;&lt;span class="section-number-3"&gt;3.2.&lt;/span&gt; Algorithms for Trees&lt;/h3&gt;
&lt;div class="outline-text-3" id="text-3-2"&gt;
&lt;p&gt;
Sometimes you don't want to flatten everything to a sequence.
You want to preserve the shape of the structure.
&lt;/p&gt;

&lt;p&gt;
It also turns out there are &lt;b&gt;efficient&lt;/b&gt; tools for building recursive data structures out of flat templated types, then folding them in to a value, unfolding a value into a structure, and fusing the two so the structure is never materialized.
The fold/unfold/fuse trio goes back to &lt;a href="https://maartenfokkinga.github.io/utwente/mmf91m.pdf"&gt;&lt;i&gt;Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire&lt;/i&gt;&lt;/a&gt; (Meijer, Fokkinga, and Paterson, 1991).
&lt;/p&gt;

&lt;p&gt;
We should standardize those tools, and provide the hooks so your current handwritten binary tree can use all the same algorithms.
&lt;/p&gt;

&lt;p&gt;
Here is yesterday's tree: &lt;code&gt;unique_ptr&lt;/code&gt; children, not even copyable, no &lt;code&gt;Fix&lt;/code&gt; anywhere.
Three ingredients, and then the fold runs over it as it is.
From the &lt;a href="https://github.com/steve-downey/tree_algorithms"&gt;tree_algorithms&lt;/a&gt; repository's examples.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Yesterday's tree.
&lt;/span&gt;&lt;span class="org-keyword"&gt;struct&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt; {
    &lt;span class="org-type"&gt;int&lt;/span&gt;                   &lt;span class="org-variable-name"&gt;value&lt;/span&gt;;
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;left&lt;/span&gt;;  &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;null = absent
&lt;/span&gt;    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;right&lt;/span&gt;; &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;null = absent
&lt;/span&gt;};

&lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-function-name"&gt;leaf&lt;/span&gt;(&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;v&lt;/span&gt;) -&amp;gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; { &lt;span class="org-keyword"&gt;return&lt;/span&gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::make_unique&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt;(Node{v, &lt;span class="org-constant"&gt;nullptr&lt;/span&gt;, &lt;span class="org-constant"&gt;nullptr&lt;/span&gt;}); }

&lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-function-name"&gt;node&lt;/span&gt;(&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;v&lt;/span&gt;, &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;l&lt;/span&gt;, &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;r&lt;/span&gt;) -&amp;gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;unique_ptr&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt; {
    &lt;span class="org-keyword"&gt;return&lt;/span&gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::make_unique&amp;lt;&lt;span class="org-type"&gt;Node&lt;/span&gt;&amp;gt;(Node{v, &lt;span class="org-constant"&gt;std&lt;/span&gt;::move(l), &lt;span class="org-constant"&gt;std&lt;/span&gt;::move(r)});
}

&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Ingredient one: one layer of the tree, child slots holding whatever
&lt;/span&gt;&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;handle type the projection deals in.
&lt;/span&gt;&lt;span class="org-keyword"&gt;template&lt;/span&gt; &amp;lt;&lt;span class="org-keyword"&gt;typename&lt;/span&gt; &lt;span class="org-type"&gt;A&lt;/span&gt;&amp;gt;
&lt;span class="org-keyword"&gt;struct&lt;/span&gt; &lt;span class="org-type"&gt;NodeF&lt;/span&gt; {
    &lt;span class="org-type"&gt;int&lt;/span&gt;              &lt;span class="org-variable-name"&gt;value&lt;/span&gt;;
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;A&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;left&lt;/span&gt;;
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;A&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;right&lt;/span&gt;;
};

&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Ingredient two: fmap for that layer — apply a function to each engaged
&lt;/span&gt;&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;child slot, left before right; the value rides along.
&lt;/span&gt;&lt;span class="org-keyword"&gt;inline&lt;/span&gt; &lt;span class="org-keyword"&gt;constexpr&lt;/span&gt; &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;fmap_node&lt;/span&gt; = [](&lt;span class="org-keyword"&gt;auto&lt;/span&gt;&amp;amp;&amp;amp; &lt;span class="org-variable-name"&gt;fn&lt;/span&gt;, &lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-keyword"&gt;auto&lt;/span&gt;&amp;amp; &lt;span class="org-variable-name"&gt;layer&lt;/span&gt;) {
    &lt;span class="org-keyword"&gt;using&lt;/span&gt; &lt;span class="org-type"&gt;A&lt;/span&gt; = &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;remove_cvref_t&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;decltype&lt;/span&gt;(*layer.left)&amp;gt;;
    &lt;span class="org-keyword"&gt;using&lt;/span&gt; &lt;span class="org-type"&gt;B&lt;/span&gt; = &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;remove_cvref_t&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;invoke_result_t&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;decltype&lt;/span&gt;(fn), &lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;A&lt;/span&gt;&amp;amp;&amp;gt;&amp;gt;;
    &lt;span class="org-keyword"&gt;return&lt;/span&gt; &lt;span class="org-type"&gt;NodeF&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;B&lt;/span&gt;&amp;gt;{layer.value,
                    layer.left ? &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;B&lt;/span&gt;&amp;gt;{fn(*layer.left)} : &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;B&lt;/span&gt;&amp;gt;{},
                    layer.right ? &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;B&lt;/span&gt;&amp;gt;{fn(*layer.right)} : &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;B&lt;/span&gt;&amp;gt;{}};
};

&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Ingredient three: the projection — expose one layer, children as raw
&lt;/span&gt;&lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;non-owning pointers into the tree we already have.
&lt;/span&gt;&lt;span class="org-keyword"&gt;inline&lt;/span&gt; &lt;span class="org-keyword"&gt;constexpr&lt;/span&gt; &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;project&lt;/span&gt; = [](&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;* &lt;span class="org-variable-name"&gt;n&lt;/span&gt;) -&amp;gt; &lt;span class="org-type"&gt;NodeF&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;*&amp;gt; {
    &lt;span class="org-keyword"&gt;return&lt;/span&gt; {n-&amp;gt;value,
            n-&amp;gt;left ? &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;*&amp;gt;{n-&amp;gt;left.get()} : &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;*&amp;gt;{},
            n-&amp;gt;right ? &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;*&amp;gt;{n-&amp;gt;right.get()} : &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;Node&lt;/span&gt;*&amp;gt;{}};
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;An order-sensitive algebra: "(left value right)" with "." marking
&lt;/span&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;an absent child pins shape and traversal order exactly.
&lt;/span&gt;    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;shape_algebra&lt;/span&gt; = [](&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-type"&gt;NodeF&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::string&amp;gt;&amp;amp; &lt;span class="org-variable-name"&gt;layer&lt;/span&gt;) -&amp;gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::string {
        &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;child&lt;/span&gt; = [](&lt;span class="org-keyword"&gt;const&lt;/span&gt; &lt;span class="org-constant"&gt;std&lt;/span&gt;::&lt;span class="org-type"&gt;optional&lt;/span&gt;&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::string&amp;gt;&amp;amp; &lt;span class="org-variable-name"&gt;c&lt;/span&gt;) { &lt;span class="org-keyword"&gt;return&lt;/span&gt; c ? *c : &lt;span class="org-constant"&gt;std&lt;/span&gt;::string(&lt;span class="org-string"&gt;"."&lt;/span&gt;); };
        &lt;span class="org-keyword"&gt;return&lt;/span&gt; &lt;span class="org-string"&gt;"("&lt;/span&gt; + child(layer.left) + &lt;span class="org-string"&gt;" "&lt;/span&gt; + &lt;span class="org-constant"&gt;std&lt;/span&gt;::to_string(layer.value) + &lt;span class="org-string"&gt;" "&lt;/span&gt; + child(layer.right) + &lt;span class="org-string"&gt;")"&lt;/span&gt;;
    };

    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;shape&lt;/span&gt; = fold_with&amp;lt;&lt;span class="org-constant"&gt;std&lt;/span&gt;::string&amp;gt;(shape_algebra, fmap_node, project, tree.get());
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
P4322, &lt;i&gt;Algorithms for Trees&lt;/i&gt;, proposes generic algorithms centered on recursive structure instead of flat external iteration: fold, unfold, and the fusion of the two, plus the hooks that let a hand-written tree use them.
&lt;/p&gt;

&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/tree_algorithms"&gt;https://github.com/steve-downey/tree_algorithms&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Algorithms for Trees&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-orgdcdd3e1" class="ox-nikola-outline-3"&gt;
&lt;h3 id="orgdcdd3e1"&gt;&lt;span class="section-number-3"&gt;3.3.&lt;/span&gt; Fingertrees&lt;/h3&gt;
&lt;div class="outline-text-3" id="text-3-3"&gt;
&lt;p&gt;
A twenty year old data structure.
&lt;a href="https://www.staff.city.ac.uk/~ross/papers/FingerTree.html"&gt;Hinze and Paterson's 2006 paper&lt;/a&gt; is still the reference, and Haskell has shipped it as &lt;a href="https://hackage.haskell.org/package/containers/docs/Data-Sequence.html"&gt;&lt;code&gt;Data.Sequence&lt;/code&gt;&lt;/a&gt; the whole time.
&lt;/p&gt;

&lt;p&gt;
That is, by the way, the same Paterson on all three foundational papers.
&lt;/p&gt;

&lt;p&gt;
It's "purely functional" and "persistent" which means that operations on the tree return a new tree rather than mutating the original tree.
Nonetheless, by clever sharing of state, it is still very efficient.
You can hand a fingertree to a long-running job on another thread and keep working on your own copy.
You don't have to pause the world while writing out state to disk.
&lt;/p&gt;

&lt;p&gt;
Further, by annotating the interior nodes, many other data structures can be efficiently modeled, using &lt;code&gt;monoids&lt;/code&gt;: a type, an associative binary operation, and an identity element.
The monoidal tag accumulates a measurement of what is held below a node, and the tree is navigated by that measure.
It can act as a sequence, a priority queue, or an interval map, all depending on the choice of measure.
&lt;/p&gt;

&lt;p&gt;
Every container in the standard library beats a fingertree at the one thing it was built for. A fingertree is merely decent at all of them at once, and a copy is O(1).
That is very hard to beat.
&lt;/p&gt;

&lt;p&gt;
A &lt;code&gt;shared_ptr&amp;lt;const vector&amp;gt;&lt;/code&gt; allows O(1) copy of the shared_ptr, but the &lt;code&gt;vector&lt;/code&gt; can't be modified by anyone else. A &lt;code&gt;fingertree&lt;/code&gt;, or any persistent data structure, can be modified without affecting anyone holding the old one. Modifications produce a new &lt;code&gt;fingertree&lt;/code&gt;, cheaply.
&lt;/p&gt;

&lt;p&gt;
Split by measure, and the original is untouched.
From the &lt;a href="https://github.com/steve-downey/fingertree"&gt;fingertree&lt;/a&gt; repository's example.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-cpp"&gt;&lt;code&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Build a persistent measured sequence 0..9; snoc appends at the back.
&lt;/span&gt;    &lt;span class="org-constant"&gt;ft&lt;/span&gt;::&lt;span class="org-type"&gt;FingerTree&lt;/span&gt;&amp;lt;&lt;span class="org-type"&gt;int&lt;/span&gt;&amp;gt; &lt;span class="org-variable-name"&gt;seq&lt;/span&gt;;
    &lt;span class="org-keyword"&gt;for&lt;/span&gt; (&lt;span class="org-type"&gt;int&lt;/span&gt; &lt;span class="org-variable-name"&gt;i&lt;/span&gt; = 0; i &amp;lt; 10; ++i)
        seq = seq.snoc(i);

    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"sequence size (measure): "&lt;/span&gt; &amp;lt;&amp;lt; seq.measure() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;

    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Split by accumulated measure: the left side is the longest prefix whose
&lt;/span&gt;    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;measure stays below the threshold; the element that reaches it goes right.
&lt;/span&gt;    &lt;span class="org-keyword"&gt;auto&lt;/span&gt; &lt;span class="org-variable-name"&gt;split&lt;/span&gt; = seq.split_at_measure(&lt;span class="org-constant"&gt;std&lt;/span&gt;::size_t{4});
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"left size:  "&lt;/span&gt; &amp;lt;&amp;lt; split.d_left.measure() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;
    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"right size: "&lt;/span&gt; &amp;lt;&amp;lt; split.d_right.measure() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;'\n'&lt;/span&gt;;

    &lt;span class="org-comment-delimiter"&gt;// &lt;/span&gt;&lt;span class="org-comment"&gt;Persistence: the split shares structure and leaves the original intact.
&lt;/span&gt;    &lt;span class="org-constant"&gt;std&lt;/span&gt;::cout &amp;lt;&amp;lt; &lt;span class="org-string"&gt;"original still has "&lt;/span&gt; &amp;lt;&amp;lt; seq.measure() &amp;lt;&amp;lt; &lt;span class="org-string"&gt;" elements\n"&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
P4325, &lt;i&gt;A Persistent Measured Sequence for the Standard Library&lt;/i&gt;, proposes a persistent measured sequence abstraction with efficient concatenation, prefix-based search, and split operations, drawing on the finger-tree literature without committing to one implementation.
&lt;/p&gt;

&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/fingertree"&gt;https://github.com/steve-downey/fingertree&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Hinze &amp;amp; Paterson's Fingertrees&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org3a64d6b" class="ox-nikola-outline-3"&gt;
&lt;h3 id="org3a64d6b"&gt;&lt;span class="section-number-3"&gt;3.4.&lt;/span&gt; Backticks For Infix&lt;/h3&gt;
&lt;div class="outline-text-3" id="text-3-4"&gt;
&lt;p&gt;
&lt;code&gt;a `f` b&lt;/code&gt; == &lt;code&gt;f(a, b)&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
This is apparently either something you have always desired, or you have no idea why anyone would ever need such a thing.
&lt;/p&gt;

&lt;p&gt;
C++26 added the backtick to the basic character set (&lt;a href="https://wg21.link/p2558"&gt;P2558&lt;/a&gt;). Nothing uses it yet.
&lt;/p&gt;

&lt;p&gt;
It's not the same as the &lt;code&gt;pizza&lt;/code&gt; operator, &lt;code&gt;|&amp;gt;&lt;/code&gt; (&lt;a href="https://wg21.link/p2011"&gt;P2011&lt;/a&gt;), although they are near each other.
&lt;/p&gt;

&lt;p&gt;
Infix makes pipelines built from the algebraic gadgets I am proposing easier to read.
Subject-verb-object is the common order in most of the native languages programmers reading this post use.
No language stacks its verbs in front the way f(g(h(x))) does.
Naming every intermediate result just to break up a chain makes the reader keep track of state that exists only to be named.
&lt;/p&gt;

&lt;p&gt;
P4307, &lt;i&gt;An Infix Operator and a Keyword Escape for C++&lt;/i&gt;, proposes two uses for the backtick, the last printable ASCII character the language can still claim: any callable as a binary operator, and a keyword escaped for use as an ordinary identifier.
Each is defined by rewrite into something the language already has, and they are proposed together because two independent claims on one character, designed separately, would end in contradiction.
&lt;/p&gt;

&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/backtick"&gt;https://github.com/steve-downey/backtick&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Infix function notation for C++
&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/llvm-project/tree/backtick"&gt;https://github.com/steve-downey/llvm-project/tree/backtick&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Backticks in LLVM&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/gcc/tree/backtick"&gt;https://github.com/steve-downey/gcc/tree/backtick&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Backticks in GCC&lt;/dd&gt;
&lt;/dl&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org172e21e" class="ox-nikola-outline-2"&gt;
&lt;h2 id="org172e21e"&gt;&lt;span class="section-number-2"&gt;4.&lt;/span&gt; "Only be sure always to call it please 'Research'" - Tom Lehrer&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-4"&gt;
&lt;p&gt;
The core ideas that run through all of this work are
&lt;/p&gt;
&lt;ol class="org-ol"&gt;
&lt;li&gt;Higher Order Functions&lt;/li&gt;
&lt;li&gt;Internal Iteration&lt;/li&gt;
&lt;li&gt;Typeclasses&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
None are at all novel.
&lt;/p&gt;

&lt;p&gt;
Higher order functions, functions that take functions as arguments, or return functions, are the central mechanism of Ranges and Senders, as well as being in Stepanov's STL.
Separation of the mechanism, or shape,  of an algorithm from the operation the algorithm performs is table stakes these days.
&lt;/p&gt;

&lt;p&gt;
Iteration is also a central concern of the STL.
Applying functions to or inspecting each element in some collection in some manner defined by the structure — abstracted away from the algorithm that applies a user operation — was Stepanov's key insight in defining Generic Programming.
The STL exposes the iteration externally, making Iterators a key component. Algorithms, Iterators,  and Containers are the triad that define the STL.
Ranges provides a bridge to internal iteration, where the iteration is not necessarily exposed.
&lt;/p&gt;

&lt;p&gt;
It has turned out that external iteration, using pointers or indices, is a source of needless safety problems.
Moving the details of unsafe operations, such as checking if an iterator is valid, or dereferenceable, into small and reused blocks of code improves safety, and correctness.
It has also turned out that there is little to no loss of performance.
Sometimes even performance improvements because the compiler can see it is lowering known safe code to unsafe implementation and can elide checks it might otherwise need to do.
Compiler middle and back ends have learned an astonishing number of tricks — often driven by other languages that have made safety a priority.
&lt;/p&gt;

&lt;p&gt;
Typeclasses are newer to C++ as an organizing principle, but not as an implementation technique.
They are merely a record that collects a coherent set of named operations together.
In a language with first class support for them the compiler or runtime will arrange to make these names available to functions constrained on them.
&lt;/p&gt;

&lt;p&gt;
I am not proposing a language extension for typeclasses.
&lt;/p&gt;

&lt;p&gt;
I am proposing pure and efficient library mechanisms for discovering and forwarding the bundle of named operations.
&lt;/p&gt;

&lt;p&gt;
Use an object holding callables with well known names, one for each operation in a related family. A concrete interface.
&lt;/p&gt;

&lt;p&gt;
Provide a generic lookup mechanism for the object so that algorithms can find the instance for the types provided to the algorithms. The typeclass instance.
&lt;/p&gt;

&lt;p&gt;
Structs, with named operations. No other required indirection. No required virtual functions. No required inheritance.
&lt;/p&gt;

&lt;p&gt;
Everything visible to the compiler — available for inlining and defunctionalization.
&lt;/p&gt;

&lt;p&gt;
The compiler's middle and back ends are extremely happy with them.
&lt;/p&gt;

&lt;p&gt;
I am proposing some more complicated machinery to help write a typeclass  instance, one that derives the rest of the operations from a few core ones.
Consumers of an instance do not care.
All they look for is how to perform one of the named operations the typeclass provides.
How it is provided is not their problem.
Purely duck typing.
&lt;/p&gt;

&lt;p&gt;
The generic programming facilities of C++26 are enough to implement these abstractions type-safely.
Even taking in to account the effects of error handling and failures.
Using these facilities also produces efficient and correct by construction code, at the cost of some debugging overhead without inlining, and some complexity in the implementation of the proposed framework for users to provide typeclass definition for their own types.
&lt;/p&gt;

&lt;p&gt;
Haskell is not the only language to use typeclasses as an organizing principle.
&lt;a href="https://lean-lang.org/"&gt;Lean&lt;/a&gt;, which the mathematicians and the machine learning people have both taken up lately, borrowed them as well.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
A type class describes a collection of overloadable operations. To overload these operations for a new type, an instance is created that contains an implementation of each operation for the new type. For example, a type class named &lt;code&gt;Add&lt;/code&gt; describes types that allow addition, and an instance of &lt;code&gt;Add&lt;/code&gt; for &lt;code&gt;Nat&lt;/code&gt; provides an implementation of addition for &lt;code&gt;Nat&lt;/code&gt;.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
From &lt;a href="https://lean-lang.org/functional_programming_in_lean/Overloading-and-Type-Classes/#type-classes"&gt;&lt;i&gt;Functional Programming in Lean&lt;/i&gt;&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org34e1536" class="ox-nikola-outline-2"&gt;
&lt;h2 id="org34e1536"&gt;&lt;span class="section-number-2"&gt;5.&lt;/span&gt; "Why in the &lt;b&gt;Standard&lt;/b&gt;"&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-5"&gt;
&lt;p&gt;
Typeclasses are shared vocabulary.
A treaty between algorithm writers, data structure writers and programmers trying to use those two together.
Standardizing the generic verbs for the operations for a typeclass allows generic re-use.
That is why we standardize things.
&lt;/p&gt;

&lt;p&gt;
A typeclass is a very lightweight adapter.
Providing the translation between the vocabulary a type would like to use for its own domain to the abstract verbs something like Traversable or Monad provides is a benefit to everyone.
&lt;/p&gt;

&lt;p&gt;
Providing the typeclass also signals how the native vocabulary of the type works.
&lt;/p&gt;

&lt;p&gt;
Anyone can write typeclass machinery for themselves.
I certainly have been for years.
Stepanov's insight was that making the interface between algorithms and containers a distinct third thing improved both algorithms and containers.
Making the iterators what each sees turns M*N into M+N.
Making them standard made them worth providing for everything, even third party code.
&lt;/p&gt;

&lt;p&gt;
We then failed to provide any support for writing iterators.
&lt;/p&gt;

&lt;p&gt;
This is a running problem.
We failed to provide support for iterators, for writing coroutine types, and initially failed to provide the extension point for writing pipable range algorithms.
Writing typeclasses is a first class part of this proposal, while still also making sure that the coupling is as minimal as I could make it.
There's no inherent requirement to use the facilities.
Algorithms and code that consume a typeclass do not care how it is implemented.
&lt;/p&gt;

&lt;p&gt;
We've also learned a lot about ABI stability and the mistakes that make evolution difficult.
The lack of names in the vtable makes for silent breaks if that layout is ever changed or extended.
This is one of the problems with locale facets in iostreams, as well as with pmr::memory_resource.
Typeclasses are not virtual interfaces, and are fully typed.
Changing a function in them can cause errors, and be a breaking change, but extending them can be a compatible, non-breaking, change, if the implementation infrastructure is used because derived operations are based on a small set of core functions.
We can even add a new alternative basis operation in terms of the existing ones.
Entirely new operation sets would instead be a new typeclass.
&lt;/p&gt;

&lt;p&gt;
Complexity of implementation is also an issue for new standard components.
There can be legitimate concerns that specialized knowledge is necessary for a high quality implementation.
This often comes up in numerical processing.
However, in this case, the implementation is fairly boring.
It is not at all complex and well within the normal realm of work for a standard library writer.
&lt;/p&gt;

&lt;p&gt;
The typeclasses being proposed are ancient.
It is highly unlikely that monoid or functor get new or different operations which would break everything.
The implementation for a particular instance can be updated with normal care as the standard typeclasses being proposed are all stateless.
User written typeclasses might have state, and that can be a useful instrumentation technique, but that is a user manageable problem.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-orgeed7343" class="ox-nikola-outline-2"&gt;
&lt;h2 id="orgeed7343"&gt;&lt;span class="section-number-2"&gt;6.&lt;/span&gt; Not Quite What I Set Out To Do&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-6"&gt;
&lt;p&gt;
One of the main use cases I set out to solve with all of this turned out to be better not done at all.
The particular problem of Unicode normalization can require many small insertions and deletions of code points in the middle of strings, and is a worst-case scenario for vector, and string.
I was originally envisioning Text types that would maintain a normalization as an invariant as the text is manipulated.
&lt;/p&gt;

&lt;p&gt;
That turns out to be unnecessary.
&lt;/p&gt;

&lt;p&gt;
While I still believe that a Unicode Text type would be a valuable addition to the standard, simply maintaining well-formedness of the underlying UTF encoded data is sufficient to support Unicode algorithms and interoperability with facilities and languages, such as Python3, that have well-formed UTF-8 as a hard requirement for bringing data into their string types.
Normalization is best done once, as needed, at the boundaries of the system.
Canonical normalization (&lt;a href="https://unicode.org/reports/tr15/"&gt;UAX #15&lt;/a&gt;) never changes the meaning of text, simply some details of representation.
Unicode algorithms generally just do not care.
&lt;/p&gt;

&lt;p&gt;
I will still be bringing the Container I had planned, since it's both very widely useful, available in several different languages already, and can solve many real world problems efficiently and safely.
Just not as a necessary part of Text.
Instead as one of many Containers that Text could be an adapter for.
&lt;/p&gt;

&lt;p&gt;
A Text adapter is, also, not on my core road map for Unicode in C++29.
Access to the primary algorithms defined by the Unicode standard is much more important, and would be, in any case, the underpinnings for a Text type.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-orgefd7584" class="ox-nikola-outline-2"&gt;
&lt;h2 id="orgefd7584"&gt;&lt;span class="section-number-2"&gt;7.&lt;/span&gt; What I want&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-7"&gt;
&lt;p&gt;
I want excellent support in the standard for algorithms that are not just processing a sequence.
&lt;/p&gt;

&lt;p&gt;
I want to take what we have learned from the STL, from std::ranges, and from std::execution, and extend the capabilities to more classes of structures.
&lt;/p&gt;

&lt;p&gt;
I want C++ to be as expressive as Python, Rust, Swift, or Haskell.
&lt;/p&gt;

&lt;p&gt;
I want to package into the standard the tools, facilities, and vocabulary that make all of this accessible to working programmers.
&lt;/p&gt;

&lt;p&gt;
Without having to go back to University and get a Maths degree specializing in Category Theory and Programming Languages.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="ox-nikola-outline-container-org4856d8f" class="ox-nikola-outline-2"&gt;
&lt;h2 id="org4856d8f"&gt;&lt;span class="section-number-2"&gt;8.&lt;/span&gt; When?&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-8"&gt;
&lt;p&gt;
Papers are forthcoming.
&lt;/p&gt;

&lt;p&gt;
Code exists.
&lt;/p&gt;

&lt;p&gt;
Public uses of the code exist, also.
&lt;/p&gt;
&lt;dl class="org-dl"&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/fixpoint"&gt;https://github.com/steve-downey/fixpoint&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Astronautics with Kmett's recursion schemes&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/compile-time-scheme"&gt;https://github.com/steve-downey/compile-time-scheme&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;A compile time &lt;del&gt;Scheme&lt;/del&gt; Common Lisp compiler&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://github.com/steve-downey/compile-time-forth"&gt;https://github.com/steve-downey/compile-time-forth&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;A compile time Forth compiler&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;
In order to keep this feasible for C++29 I am keeping the papers minimal and focused.
It's also why there are several papers, not a "One Typeclass Proposal" paper.
This means possibly leaving some work undone, without foreclosing it.
The largest gap right now is a Monad typeclass.
It's clear how to do one, and what would go in it.
But it's not necessary for solving the problems that any of the papers I'm working on are trying to solve.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>draft</category><guid>https://sdowney.org/posts/trees-and-transposition/</guid><pubDate>Mon, 07 Sep 2026 22:06:21 GMT</pubDate></item></channel></rss>