<p>Say I have a loop that looks like this:</p>
<pre><code>for i in range(1, 10) {
   print(i)
}
</code></pre>
<p>Now I want to take the same sequence in reverse, and filter out even numbers. I might also allow the function to work with arguments like <code>range(10, 1)</code> but let's ignore that option for now. I'll use other things called <code>reverse</code> and <code>filter</code> that work on any sequence. I'm wondering about syntax possibilities.</p>
<pre><code>for i in filter(reverse(range(1, 10)), odd) { ...
for i in range(1, 10).reverse().filter(odd) { ...
for i in range(1, 10) | reverse | filter(odd) { ...
for i in range(1, 10) ⏵ reverse ⏵ filter(odd) { ...
for i in range(1, 10) → reverse → filter(odd) { ...
for i in range 1 10 → reverse → filter odd { ...
</code></pre>
<p>The first case I find harder to read as the function calls pile up.</p>
<p>With the second case (extension methods), I wonder if they are good enough, and obviate the need for a special &quot;pipeline&quot; syntax.</p>
<p>The next three are all similar, except I'm considering using some Unicode for operators unlike traditional programming languages. We have all these nice glyphs; why not use them?</p>
<p>The last one is based on Haskell, which I haven't used much, but I guess syntax like that without <code>(...)</code> can also work.</p>
<p>I know C++ is using <code>|</code> for its <code>std::ranges</code> pipelines. It looks like Julia uses <code>|&gt;</code>. What else is out there?</p>

<functions><operators><syntactic-sugar>
Prior art on pipelines of function calls
CC BY-SA 4.0
2023-07-21T15:56:03.140Z
Personally, I really dislike unicode operators in languages. Mostly because I can't type them with my physical keyboard, save for horrbily overcomplicated ways like `Alt + '+' + DEADBEEF` or copy-pasting it every time
abel1502
CC BY-SA 4.0
2023-07-21T15:59:53.343Z
@abel1502 Have you ever used an editor with something like Agda-mode? You type something like `\forall` and it automatically becomes `∀` when you finish typing. No modifiers needed
David Young
CC BY-SA 4.0
2023-07-21T16:05:56.443Z
@DavidYoung That's cool, but then why not use `\forall` itself in the language, if that's what the user types anyway?
abel1502
CC BY-SA 4.0
2023-07-21T16:56:29.923Z
@abel1502 Because code is meant to be _read_ as much as written. For this reason I'm considering some unicode, with editor help like David described.
Rob N
CC BY-SA 4.0
2023-07-21T17:03:07.227Z
@RobN, well, yes, and I think having non-ascii characters hinders readability, because you can't mentally (or orally) spell out the code unless you know the way it's spelled in the editor. For instance, what should I call the `⏵` operator when talking to a colleague? Besides, an abundance of operators with short names tempts programmers to abuse them, which is generally accepted to hinder code quality and readability as well
abel1502
CC BY-SA 4.0
2023-07-21T17:46:39.820Z
Whatever notation you use, `filter` is a very bad function name, languages seem to be contradictory about if this acts like a `filter` that removes things or a `filter` to let them through. It's better to have `remove` or `reject` or `keep`, anything that is less ambiguous
coredump
CC BY-SA 4.0
2023-07-21T18:06:07.627Z
F# uses `|>`, shells use `|`
Eldritch Conundrum
CC BY-SA 4.0
2023-07-21T18:48:29.480Z
What do you mean by "good-enough" in *I wonder if they are good enough, and obviate the need for a special "pipeline" syntax.*? I find the syntax is nice, but maybe you are talking about runtime performance? do you mean that with a special syntax you could make the iterator more efficient?
coredump
CC BY-SA 4.0
2023-07-21T19:08:02.980Z
Good point about `filter` vs `remove/keep`. By "good enough" I meant the syntax, and anything else I might not have thought of yet. I'm not aware of any performance issue that depends on the syntax choice.
Rob N
CC BY-SA 4.0
2023-07-21T23:47:07.537Z
@abel1502 You'd call ⏵ a right-pointing triangle. Also check out XCompose, it's already standard on X, X.Org and Wayland, and with Windows ports. I personally cannot rely on ASCII because the Government doesn't support it.
Longinus
CC BY-SA 4.0
2023-07-22T06:08:20.357Z
For what it's worth, the font my browser is using to display this webpage doesn't seem to have a proper glyph for ⏵. My hardware's a bit old but my browser and OS are definitely up to date.
Karl Knechtel
CC BY-SA 4.0
2023-07-22T07:30:56.137Z
Unicode operators can be a problem since there are many Unicode glyphs which at first glance look similar to each other. My feeling is that they're OK in the scope of a single compilation unit or possibly single project, but an attempt to define a Unicode operator to represent a complex operator at the scale of a published library is hazardous.
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-22T17:23:16.237Z
Please do not force me to use an IDE.
Adam Barnes
CC BY-SA 4.0
2023-07-23T01:12:44.627Z
@abel1502, yes, do check XCompose.  I use it all the time. I've set the menu-key (beside the right ctrl key) to be my compose key, and I can rapidly type many non-ascii characters without moving my hands from the usual typing position. After a while it becomes automatic, no thinking required. `⌷oo` becomes the degree symbol, `⌷c,` becomes a French 'ç', `⌷=>` becomes '⇒', etc., with most characters requiring only three key strokes, and most of the sequences being fairly obvious and easy to remember.
Ray Butterworth
CC BY-SA 4.0
2023-07-31T15:45:49.783Z
C++ is also [considering `|>` as a pipeline-rewrite operator](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2011r1.html):  a general mechanism to use its left-hand side as first argument to function call on the right-hand side.
Toby Speight
<p>It's not prior art, but a suggestion:</p>
<h2><code>:=</code> for special purpose pipeline start marker</h2>
<p>So you can have both, a special pipeline syntax that uses no special inter pipe symbol, and the rest of language is unaffected.</p>
<p>A pipeline sequence expects some data to be emitted from one coroutine to another, and may or may not produce data at end. It's akin to saying that each pipeline stage is a small program that reads a local <code>stdin</code> and outputs to a local <code>stdout</code>, but in this case, probably reads from typed channel readers and outputs to typed channel writers.</p>
<p>This may be relevant if your language will have support for cooperative routines or full blow async/await channel pipeline.</p>
<p>Something like this:</p>
<pre class="lang-python prettyprint-override"><code># Use

var odd = ...;                               // normal syntax
var seq := range(1, 10) reverse filter(odd); // pipe application syntax
foreach( var filtered in seq )
    // ...

# Declared as

def asyncio int range( _ , int start , int end , int step = 1 ): // no input
def asyncio T reverse (T arg):                    // async channel interface
def asyncio T filter (T arg , Predicate&lt;T&gt; pred): // asyncio w/ extra params
def T filter_odd (T arg, Predicate&lt;T&gt; pred):      // normal syntax

# Signature desugars to and is implemented as

def async AsyncWriter&lt;T&gt; reverse (AsyncReader&lt;T&gt; arg):
    var stack = new Stack&lt;T&gt;();
    while ( var cont, data = arg.ReadAsync() )
        stack.Push( data );
    while ( stack.HasData )
        yield return stack.Pop();

def async AsyncWriter&lt;T&gt; filter (AsyncReader&lt;T&gt; arg, Predicate&lt;T&gt; pred):
    while ( var cont, data = arg.ReadAsync() )
        if ( pred.Invoke( data ) )
            return yield data;

# Pipe application accepts normal and async/asyncio fuctions,
# but it may inject Optionals in chain. Async channel represents
# better no data as &quot;no transmission&quot; / send nothing.

def Optional&lt;T&gt; filter_odd (T data):
    if ( num % 2 &gt; 0 )
        return data;
    else
        return null;
</code></pre>

CC BY-SA 4.0
2023-07-22T18:58:32.260Z
2023-07-31T13:50:41.457Z
2023-07-31T13:50:41.457Z
André L F S Bacci
<p>There are several different traditions for this in real-world languages. Many of them have colonised previously-unused punctuation, rather than having a strong design ethos to them. The semantics also vary: some pass a value as the next argument to a function (or only to a curried application), some instead pass it as an inserted <em>first</em> argument to a function call, some have reverse or unpacking pipelines, some permit only single-parameter functions, and some only have stream processing.</p>
<hr />
<p><strong>Haskell</strong> has multiple in its standard library:</p>
<ul>
<li><code>&amp;</code> has type <code>a -&gt; (a -&gt; b) -&gt; b</code>, the classical left-to-right pipeline providing the value on the left as the next argument to the function on the right. This is not in the Prelude but can be imported from Data.Function; it is the <a href="https://hoogle.haskell.org/?hoogle=a%20-%3E%20(a%20-%3E%20b)%20-%3E%20b" rel="noreferrer">most common realisation of this type in Hoogle</a>, but there are others in other libraries. You could use this as something like <code>range 1 10 &amp; reverse &amp; filter odd</code>.</li>
<li><code>$</code> has type <code>(a -&gt; b) -&gt; a -&gt; b</code>, reverse pipeline right-to-left. This one <em>is</em> in the Prelude. You could use this as something like <code>filter odd $ reverse $ range 1 10</code>.</li>
<li><code>$!</code> is <code>$</code> but strict in the value argument.</li>
<li>Versions of the operation are also provided for functors (<code>&lt;&amp;&gt;</code> and <code>&lt;$&gt;</code>), applicative functors (<code>&lt;**&gt;</code> and <code>&lt;*&gt;</code>), and other types, most obviously monadic bind <code>&gt;&gt;=</code>.</li>
<li><code>.</code> performs the function composition without the final application to a value.</li>
</ul>
<p>The conventional pipeline operator in <strong>R</strong> is <code>%&gt;%</code>. It is a library operator from the ubiquitous <a href="https://magrittr.tidyverse.org/reference/pipe.html" rel="noreferrer">dplyr and magrittr packages</a>, and it works a little differently to the others — it's in effect a macro rewrite that inserts the left-hand value as the <em>first</em> argument of the function call written on the right:</p>
<pre class="lang-r prettyprint-override"><code>1:10 %&gt;% rev %&gt;% filt(odd)
</code></pre>
<p>would expect <code>filt</code> to be defined as <code>function(vector, predicate)</code>. This is the opposite order to the Haskell version. Note also that the <code>odd</code> predicate needed to be parenthesised, to make <code>filt(odd)</code> a function call. There are many other third-party pipelining operators as well, and support in this one for inserting the value at a placeholder position.</p>
<p>Several languages include <code>|&gt;</code> for pipelining, but with differing semantics:</p>
<ul>
<li><strong>F#</strong> <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/" rel="noreferrer">uses</a> <code>|&gt;</code> as its main pipe operator, passing the value on the left as the next argument to the function on the right. You could use this as something like <code>range 1 10 |&gt; List.rev |&gt; List.filter odd</code>. It also uses <code>||&gt;</code> for a tuple-unpacking version and <code>&lt;|</code> for the reverse order. <code>&gt;&gt;</code> and <code>&lt;&lt;</code> perform unapplied composition. Elm <a href="https://elm-lang.org/docs/syntax#operators" rel="noreferrer">uses</a> these as well.</li>
<li>OCaml <a href="https://v2.ocaml.org/api/Stdlib.html#1_Compositionoperators" rel="noreferrer">has</a> <code>|&gt;</code> since version 4, but not the others from F#.</li>
<li><strong>Hack</strong> uses <code>|&gt;</code> <a href="https://docs.hhvm.com/hack/expressions-and-operators/pipe" rel="noreferrer">with explicit placeholders</a> for the piped value on the right-hand side: <code>range(1, 10) |&gt; Vec\reverse($$) |&gt; Vec\filter($$, $n ==&gt; $n % 2 == 1)</code> inserts the argument in place of <code>$$</code>.</li>
<li><strong>Julia</strong> also <a href="https://docs.julialang.org/en/v1/base/punctuation/" rel="noreferrer">uses</a> <code>|&gt;</code>, and only for single-parameter functions, but its macro support allows libraries to extend this to provide placeholders for the argument value.</li>
<li><strong>Elixir</strong> has <code>|&gt;</code> too, but working like in R rather than F#.</li>
<li>The <a href="https://github.com/tc39/proposal-pipeline-operator" rel="noreferrer">TC39 proposal for JavaScript pipelines</a> uses this operator with Hack semantics and <code>%</code> as the placeholder token.</li>
</ul>
<p><strong>Concatenative languages</strong> use juxtaposition to represent this pipelining (and function composition in general). Mere adjacency is sufficient to pipeline the output of one function into the next already. This holds for stack-based Forth, Kitten, Joy, and others, and for inline ones like Om or Kihi.</p>
<p><strong>Unix shell</strong> languages <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_02" rel="noreferrer">use</a> <code>|</code> to compose stream pipelines, as do PowerShell object pipelines and many other inspired languages. These are connecting input and outputs streams, rather than nested function applications. <strong>jq</strong>, being quasi-concatenative, has <em>both</em> juxtaposition and <code>|</code> for pipeline steps, and they can be used in slightly different places; the input value is out of band and not a parameter regardless.</p>
<p><strong>Raku</strong> uses the pretty verbose <a href="https://docs.raku.org/routine/andthen" rel="noreferrer"><code>andthen</code></a>, with some short-circuiting semantics, and elements of placeholders and method-call shorthands. This is borderline to constitute a pipeline.</p>
<p>Any language with <a href="https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax" rel="noreferrer">uniform function call syntax</a> provides pipelining via its method application operator, typically <code>.</code>. This typically provides the left-hand side as the first parameter of the function, but some approaches allow specifying the receiver in the declaration. This does require an increased level of multiple dispatch, but no new syntax at the call site. Extension methods, as in C#, give a more restricted version of the same thing. In either case, you'd expect to write something like <code>range(1, 10).reverse().filter(odd)</code> as in your example.</p>
<hr />
<p>There is a wide variety of syntax in use and subtly or drastically different semantics between existing languages. There isn't any visible coupling between the syntactic form in use and the behavioural design of the operation, so fixing one doesn't point at a specific tradition for the other. Many cases are simply an available symbol, or a symbol borrowed from another language but given quite different meaning locally.</p>

CC BY-SA 4.0
2023-07-22T05:48:41.267Z
2023-07-22T05:58:22.337Z
2023-07-22T05:58:22.337Z
Michael Homer
CC BY-SA 4.0
2023-07-22T22:13:25.393Z
I'd just like to note, to avoid confusion, that Rust uses the term “uniform function call syntax”, but for something different than what's discussed in this answer.
xigoi
CC BY-SA 4.0
2023-07-23T02:15:40.030Z
More specifically, the Rust project formerly used "uniform function call syntax" for *both* applying a method using the same syntax as for a free function and for (the proposed feature of) applying a free function using method call syntax, before later renaming the latter to "uniform method call syntax" to remove the ambiguity.
user570286
CC BY-SA 4.0
2023-07-23T09:08:58.100Z
Nitpick/update: the first pipe operator in R was `%>%` from `magrittr`, but since R 4.1 the pipe operator `|>` has been a core feature of the language.  The semantics are similar to `%>%`, although it is a bit less flexible; `x |> f(y) |> g()` is treated by the interpreter to `g(f(x, y))`.  Since R 4.2, the "piped in" argument can be something other than the first, using `_` as a placeholder, but only for named arguments; e.g. `x |> f() |> g(y, data = _)` results in `g(y, data = f(x))`.  The `magrittr` placeholder, `.`, can appear multiple times in any context, e.g. `x %>% f(y, ., sum(.))`.
brendan
<h1><code></code></h1>
<p>APLs just let their functions take arguments on the right and a higher-order functions take a single functions on the left, thereby allowing you to chain everything from right to left:</p>
<pre><code>for i in odd filter reverse range 1 10
</code></pre>
<p>You can try this in an actual APL by defining the required <code>odd</code>, <code>filter</code>, <code>reverse</code>, and <code>range</code>:</p>
<pre><code>odd←{2|⍵}
filter←{(⍺⍺ ⍵)/⍵}
reverse←⌽
range←⊃(⊣,+∘⍳)-⍨/
</code></pre>
<p>Now, running</p>
<pre><code>:For i :In odd filter reverse range 1 10
    ⎕←i
:EndFor
</code></pre>
<p>prints:</p>
<pre><code>9
7
5
3
1
</code></pre>
<p><a href="https://ato.pxeger.com/run?1=m70qpTIxJz89PrEgZ8HN0PyUlEdtE6qNah71bq3lSsvMKUktAgloPOrdBUQKQGFNfbBcUWpZalFxKlDyUc9erqLEvHQwu6tZ41HXYh3tRx0zHvVu1tR91LtCf2lpSZquxU0bK7f8IoVMBSvPPAWgPQoQ0xWgBimAjVAwVDA04FIAgkd9U4HmZXJZuealAPVBzFgApaA0AA" rel="noreferrer" title="APL (Dyalog) – Attemot This Online">Attempt this online!</a></p>

CC BY-SA 4.0
2023-07-21T16:00:12.873Z
2023-07-21T16:00:12.873Z
Adám
CC BY-SA 4.0
2023-07-21T16:36:25.610Z
Along similar lines, Forth, in which the stack mechanism means that everything is automatically a "pipeline".  If it had complex types like ranges, this would read very simply as `1 10 RANGE REVERSE ' ODD? FILTER FOR I ...`
Nate Eldredge
CC BY-SA 4.0
2023-07-22T07:33:25.637Z
Agreeing with Adam, APL also had operator composition.
Mark Morgan Lloyd
<h2>LINQ</h2>
<p>Why use operators when you could use words? The syntax is basically SQL with a different clause order:</p>
<pre class="lang-cs prettyprint-override"><code>var filteredBackwardsRange =
  from num in Enumerable.Range(1, 10)
  where IsOdd(num)
  orderby num descending
  select num;

foreach (var i in filteredBackwardsRange)
{
  // ...
}
</code></pre>
<p>This looks cool, but every project I've worked on that uses LINQ prefers to call the methods explicitly:</p>
<pre class="lang-cs prettyprint-override"><code>var filteredBackwardsRange = Enumerable.Range(1, 10)
  .Reverse()
  .Where(IsOdd);

foreach (var i in filteredBackwardsRange)
{
  // ...
}
</code></pre>
<p>LINQ is not only a bit more verbose, it requires more work on the parser's side, and isn't extensible. (In fact, <code>Reverse</code> is one of the ones that doesn't have a keyword equivalent, hence <code>orderby descending</code> in the first snippet.) I can't honestly recommend it in a new language, but it does exist.</p>

CC BY-SA 4.0
2023-07-23T00:05:03.053Z
2023-07-23T00:05:03.053Z
Bbrk24
<h1>Composition Macros</h1>
<p>Clojure supplies <a href="https://clojure.org/guides/threading_macros" rel="nofollow noreferrer">threading macros</a>. Basically, you call them like functions and they do the function chaining at compile-time.</p>
<pre><code>range(1, 10) ⏵ reverse ⏵ filter(odd)
</code></pre>
<p>This example would look something like</p>
<pre><code>(-&gt;&gt; (range 1 10) reverse (filter odd))
</code></pre>
<p>I could see this manifesting in a non-Lisp as looking something like</p>
<pre><code>-&gt;&gt;(range(1, 10), reverse, filter(odd))
</code></pre>
<p>If you're going the Ruby way and not requiring parentheses for the top-level function call, this could be simplified to</p>
<pre><code>-&gt;&gt; range(1, 10), reverse, filter(odd)
</code></pre>

CC BY-SA 4.0
2023-07-22T01:14:41.157Z
2023-07-22T01:14:41.157Z
Silvio Mayolo
# Prior art on pipelines of function calls
Posted by: username_0 on 2023-07-21
Say I have a loop that looks like this:
for i in range(1, 10) {
   print(i)
}

Now I want to take the same sequence in reverse, and filter out even numbers. I might also allow the function to work with arguments like range(10, 1) but let's ignore that option for now. I'll use other things called reverse and filter that work on any sequence. I'm wondering about syntax possibilities.
for i in filter(reverse(range(1, 10)), odd) { ...
for i in range(1, 10).reverse().filter(odd) { ...
for i in range(1, 10) | reverse | filter(odd) { ...
for i in range(1, 10) ⏵ reverse ⏵ filter(odd) { ...
for i in range(1, 10) → reverse → filter(odd) { ...
for i in range 1 10 → reverse → filter odd { ...

The first case I find harder to read as the function calls pile up.
With the second case (extension methods), I wonder if they are good enough, and obviate the need for a special "pipeline" syntax.
The next three are all similar, except I'm considering using some Unicode for operators unlike traditional programming languages. We have all these nice glyphs; why not use them?
The last one is based on Haskell, which I haven't used much, but I guess syntax like that without (...) can also work.
I know C++ is using | for its std::ranges pipelines. It looks like Julia uses |>. What else is out there?
**Tags:** functions operators syntactic-sugar
> **Comments:**
> **username_1**: Personally, I really dislike unicode operators in languages. Mostly because I can't type them with my physical keyboard, save for horrbily overcomplicated ways like `Alt + '+' + DEADBEEF` or copy-pasting it every time  
> **username_2**: @abel1502 Have you ever used an editor with something like Agda-mode? You type something like `\forall` and it automatically becomes `∀` when you finish typing. No modifiers needed  
> **username_1**: @DavidYoung That's cool, but then why not use `\forall` itself in the language, if that's what the user types anyway?  
> **username_0**: @abel1502 Because code is meant to be _read_ as much as written. For this reason I'm considering some unicode, with editor help like David described.  
> **username_1**: @RobN, well, yes, and I think having non-ascii characters hinders readability, because you can't mentally (or orally) spell out the code unless you know the way it's spelled in the editor. For instance, what should I call the `⏵` operator when talking to a colleague? Besides, an abundance of operators with short names tempts programmers to abuse them, which is generally accepted to hinder code quality and readability as well  
> **username_3**: Whatever notation you use, `filter` is a very bad function name, languages seem to be contradictory about if this acts like a `filter` that removes things or a `filter` to let them through. It's better to have `remove` or `reject` or `keep`, anything that is less ambiguous  
> **username_4**: F# uses `|>`, shells use `|`  
> **username_3**: What do you mean by "good-enough" in *I wonder if they are good enough, and obviate the need for a special "pipeline" syntax.*? I find the syntax is nice, but maybe you are talking about runtime performance? do you mean that with a special syntax you could make the iterator more efficient?  
> **username_0**: Good point about `filter` vs `remove/keep`. By "good enough" I meant the syntax, and anything else I might not have thought of yet. I'm not aware of any performance issue that depends on the syntax choice.  
> **username_5**: @abel1502 You'd call ⏵ a right-pointing triangle. Also check out XCompose, it's already standard on X, X.Org and Wayland, and with Windows ports. I personally cannot rely on ASCII because the Government doesn't support it.  
> **username_6**: For what it's worth, the font my browser is using to display this webpage doesn't seem to have a proper glyph for ⏵. My hardware's a bit old but my browser and OS are definitely up to date.  
> **username_7**: Unicode operators can be a problem since there are many Unicode glyphs which at first glance look similar to each other. My feeling is that they're OK in the scope of a single compilation unit or possibly single project, but an attempt to define a Unicode operator to represent a complex operator at the scale of a published library is hazardous.  
> **username_8**: Please do not force me to use an IDE.  
> **username_9**: @abel1502, yes, do check XCompose.  I use it all the time. I've set the menu-key (beside the right ctrl key) to be my compose key, and I can rapidly type many non-ascii characters without moving my hands from the usual typing position. After a while it becomes automatic, no thinking required. `⌷oo` becomes the degree symbol, `⌷c,` becomes a French 'ç', `⌷=>` becomes '⇒', etc., with most characters requiring only three key strokes, and most of the sequences being fairly obvious and easy to remember.  
> **username_10**: C++ is also [considering `|>` as a pipeline-rewrite operator](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2011r1.html):  a general mechanism to use its left-hand side as first argument to function call on the right-hand side.  
---
## 5 answers
### Answer by username_12 on 2023-07-22. Score: 15
There are several different traditions for this in real-world languages. Many of them have colonised previously-unused punctuation, rather than having a strong design ethos to them. The semantics also vary: some pass a value as the next argument to a function (or only to a curried application), some instead pass it as an inserted first argument to a function call, some have reverse or unpacking pipelines, some permit only single-parameter functions, and some only have stream processing.

Haskell has multiple in its standard library:

& has type a -> (a -> b) -> b, the classical left-to-right pipeline providing the value on the left as the next argument to the function on the right. This is not in the Prelude but can be imported from Data.Function; it is the most common realisation of this type in Hoogle, but there are others in other libraries. You could use this as something like range 1 10 & reverse & filter odd.
$ has type (a -> b) -> a -> b, reverse pipeline right-to-left. This one is in the Prelude. You could use this as something like filter odd $ reverse $ range 1 10.
$! is $ but strict in the value argument.
Versions of the operation are also provided for functors (<&> and <$>), applicative functors (<**> and <*>), and other types, most obviously monadic bind >>=.
. performs the function composition without the final application to a value.

The conventional pipeline operator in R is %>%. It is a library operator from the ubiquitous dplyr and magrittr packages, and it works a little differently to the others — it's in effect a macro rewrite that inserts the left-hand value as the first argument of the function call written on the right:
1:10 %>% rev %>% filt(odd)

would expect filt to be defined as function(vector, predicate). This is the opposite order to the Haskell version. Note also that the odd predicate needed to be parenthesised, to make filt(odd) a function call. There are many other third-party pipelining operators as well, and support in this one for inserting the value at a placeholder position.
Several languages include |> for pipelining, but with differing semantics:

F# uses |> as its main pipe operator, passing the value on the left as the next argument to the function on the right. You could use this as something like range 1 10 |> List.rev |> List.filter odd. It also uses ||> for a tuple-unpacking version and <| for the reverse order. >> and << perform unapplied composition. Elm uses these as well.
OCaml has |> since version 4, but not the others from F#.
Hack uses |> with explicit placeholders for the piped value on the right-hand side: range(1, 10) |> Vec\reverse($$) |> Vec\filter($$, $n ==> $n % 2 == 1) inserts the argument in place of $$.
Julia also uses |>, and only for single-parameter functions, but its macro support allows libraries to extend this to provide placeholders for the argument value.
Elixir has |> too, but working like in R rather than F#.
The TC39 proposal for JavaScript pipelines uses this operator with Hack semantics and % as the placeholder token.

Concatenative languages use juxtaposition to represent this pipelining (and function composition in general). Mere adjacency is sufficient to pipeline the output of one function into the next already. This holds for stack-based Forth, Kitten, Joy, and others, and for inline ones like Om or Kihi.
Unix shell languages use | to compose stream pipelines, as do PowerShell object pipelines and many other inspired languages. These are connecting input and outputs streams, rather than nested function applications. jq, being quasi-concatenative, has both juxtaposition and | for pipeline steps, and they can be used in slightly different places; the input value is out of band and not a parameter regardless.
Raku uses the pretty verbose andthen, with some short-circuiting semantics, and elements of placeholders and method-call shorthands. This is borderline to constitute a pipeline.
Any language with uniform function call syntax provides pipelining via its method application operator, typically .. This typically provides the left-hand side as the first parameter of the function, but some approaches allow specifying the receiver in the declaration. This does require an increased level of multiple dispatch, but no new syntax at the call site. Extension methods, as in C#, give a more restricted version of the same thing. In either case, you'd expect to write something like range(1, 10).reverse().filter(odd) as in your example.

There is a wide variety of syntax in use and subtly or drastically different semantics between existing languages. There isn't any visible coupling between the syntactic form in use and the behavioural design of the operation, so fixing one doesn't point at a specific tradition for the other. Many cases are simply an available symbol, or a symbol borrowed from another language but given quite different meaning locally.
> **Comments:**
> **username_13** (2023-07-22): I'd just like to note, to avoid confusion, that Rust uses the term “uniform function call syntax”, but for something different than what's discussed in this answer.  
> **username_14** (2023-07-23): More specifically, the Rust project formerly used "uniform function call syntax" for *both* applying a method using the same syntax as for a free function and for (the proposed feature of) applying a free function using method call syntax, before later renaming the latter to "uniform method call syntax" to remove the ambiguity.  
> **username_15** (2023-07-23): Nitpick/update: the first pipe operator in R was `%>%` from `magrittr`, but since R 4.1 the pipe operator `|>` has been a core feature of the language.  The semantics are similar to `%>%`, although it is a bit less flexible; `x |> f(y) |> g()` is treated by the interpreter to `g(f(x, y))`.  Since R 4.2, the "piped in" argument can be something other than the first, using `_` as a placeholder, but only for named arguments; e.g. `x |> f() |> g(y, data = _)` results in `g(y, data = f(x))`.  The `magrittr` placeholder, `.`, can appear multiple times in any context, e.g. `x %>% f(y, ., sum(.))`.  
---
### Answer by username_16 on 2023-07-21. Score: 6
APLs just let their functions take arguments on the right and a higher-order functions take a single functions on the left, thereby allowing you to chain everything from right to left:
for i in odd filter reverse range 1 10

You can try this in an actual APL by defining the required odd, filter, reverse, and range:
odd←{2|⍵}
filter←{(⍺⍺ ⍵)/⍵}
reverse←⌽
range←⊃(⊣,+∘⍳)-⍨/

Now, running
:For i :In odd filter reverse range 1 10
    ⎕←i
:EndFor

prints:
9
7
5
3
1

Attempt this online!
> **Comments:**
> **username_17** (2023-07-21): Along similar lines, Forth, in which the stack mechanism means that everything is automatically a "pipeline".  If it had complex types like ranges, this would read very simply as `1 10 RANGE REVERSE ' ODD? FILTER FOR I ...`  
> **username_7** (2023-07-22): Agreeing with Adam, APL also had operator composition.  
---
### Answer by username_18 on 2023-07-23. Score: 4
LINQ
Why use operators when you could use words? The syntax is basically SQL with a different clause order:
var filteredBackwardsRange =
  from num in Enumerable.Range(1, 10)
  where IsOdd(num)
  orderby num descending
  select num;

foreach (var i in filteredBackwardsRange)
{
  // ...
}

This looks cool, but every project I've worked on that uses LINQ prefers to call the methods explicitly:
var filteredBackwardsRange = Enumerable.Range(1, 10)
  .Reverse()
  .Where(IsOdd);

foreach (var i in filteredBackwardsRange)
{
  // ...
}

LINQ is not only a bit more verbose, it requires more work on the parser's side, and isn't extensible. (In fact, Reverse is one of the ones that doesn't have a keyword equivalent, hence orderby descending in the first snippet.) I can't honestly recommend it in a new language, but it does exist.
---
### Answer by username_19 on 2023-07-22. Score: 4
Composition Macros
Clojure supplies threading macros. Basically, you call them like functions and they do the function chaining at compile-time.
range(1, 10) ⏵ reverse ⏵ filter(odd)

This example would look something like
(->> (range 1 10) reverse (filter odd))

I could see this manifesting in a non-Lisp as looking something like
->>(range(1, 10), reverse, filter(odd))

If you're going the Ruby way and not requiring parentheses for the top-level function call, this could be simplified to
->> range(1, 10), reverse, filter(odd)
---
### Answer by username_11 on 2023-07-22. Score: 3
It's not prior art, but a suggestion:
:= for special purpose pipeline start marker
So you can have both, a special pipeline syntax that uses no special inter pipe symbol, and the rest of language is unaffected.
A pipeline sequence expects some data to be emitted from one coroutine to another, and may or may not produce data at end. It's akin to saying that each pipeline stage is a small program that reads a local stdin and outputs to a local stdout, but in this case, probably reads from typed channel readers and outputs to typed channel writers.
This may be relevant if your language will have support for cooperative routines or full blow async/await channel pipeline.
Something like this:
# Use

var odd = ...;                               // normal syntax
var seq := range(1, 10) reverse filter(odd); // pipe application syntax
foreach( var filtered in seq )
    // ...

# Declared as

def asyncio int range( _ , int start , int end , int step = 1 ): // no input
def asyncio T reverse (T arg):                    // async channel interface
def asyncio T filter (T arg , Predicate pred): // asyncio w/ extra params
def T filter_odd (T arg, Predicate pred):      // normal syntax

# Signature desugars to and is implemented as

def async AsyncWriter reverse (AsyncReader arg):
    var stack = new Stack();
    while ( var cont, data = arg.ReadAsync() )
        stack.Push( data );
    while ( stack.HasData )
        yield return stack.Pop();

def async AsyncWriter filter (AsyncReader arg, Predicate pred):
    while ( var cont, data = arg.ReadAsync() )
        if ( pred.Invoke( data ) )
            return yield data;

# Pipe application accepts normal and async/asyncio fuctions,
# but it may inject Optionals in chain. Async channel represents
# better no data as "no transmission" / send nothing.

def Optional filter_odd (T data):
    if ( num % 2 > 0 )
        return data;
    else
        return null;
---
