-
-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Request: Add pipeline operator #165
Comments
Can you provide some motivation for why this would be desirable? Every RFC should contain some motivation as to why it is desirable. Even requests. Please note in case you are aware. Opening an issue such as this is a request for another human (other than you) to write up the full RFC so the more details you provide them, the better. |
What's the pipeline operators ?The pipeline operator let url = "%21" |> decodeURI() The equivalent call in traditional syntax looks like this: let url = decodeURI("%21") The pipe operator Why need pipeline operators ?Pipe Operator allows a clear, concise expression of the programmer's intent. fun inc[A: (Real[A] val & Number) = I32](x: A): A => x+1
fun double[A: (Real[A] val & Number) = I32] (x: A): A => x*2
fun print[A: (Real[A] val & Number) = I32](x: A) => _env.out.print(x.string())
// without pipeline operator
let x: I32 = 3
let x'= inc(x)
let x''= double(x')
print(x'') //8
// with pipeline operator
3 |> inc() |> double() |> print() //8
// without pipeline operator
print(add(1,double(inc(double(double(5)))))) // 43
// with pipeline operator
5 |> double() |> double() |> inc() |> double() |>> add(1) |> print() // 43
// without pipeline operator
let arr: Array[I32] ref = [1;2;3;4;5]
let arr2 = Seqs.map(arr, Num.mul(2))
let arr3 = Seqs.reverse(arr2)
let arr4 =Seqs.join(arr3, "=")
lSeqs.trace(arr4)
//prints:
"10=8=6=4=2"
// with pipeline operator
[1;2;3;4;5]
|> Seqs.map(Num.mul(2))
|> Seqs.reverse()
|> Seqs.join("=")
|> Seqs.trace()
//prints:
"10=8=6=4=2"
// without pipeline operator
let str = "abc\ndef\nghi"
let arr = Str.lines(str) // ["abc"; "def"; "ghi"]
let arr2 = Seqs.map(arr, Str.upper) // ["ABC"; "DEF"; "GHI"]
let arr3 = Seqs.map(arr, Str.reverse) //["CBA"; "FED"; "IHG"]
let path = Seqs.join(arr3, "/") // "CBA/FED/IHG"
let path_win = Str.winpath(path) // "CBA\\FED\\IHG"
let dirname = Str.dirname(path_win) //"IHG"
// with pipeline operator
"abc\ndef\nghi"
|>Str.lines()
|>Seqs.map(Str.upper)
|>Seqs.map(Str.reverse)
|>Seqs.join("/")
|>Str.winpath
|>Str.dirname //prints: "IHG" The return value of each function is used as the first argument of the next function in the pipe. It's a beautiful expression that makes the intent of the programmer clear. How to implements pipeline operators ?I do n’t have much say on how to achieve it, but only contribute a possible implementation method, just for reference: primitive Num[A: (Real[A] val & Number) = I32]
fun inc(x: A): A => x+1
fun double (x: A): A => x*2
fun add(a: A, b: B): A => a+b
fun print(x: A, env: Env) => env.out.print(x.string())
fun trace(env: Env, x: A) => env.out.print(x.string()) Design the pipeline as a 3 |> Num~inc() |> Num~add(3) |>> Num~trace(env) |
Here are some pipeline usage in other languages: Javascript Pipeline: React Pipeline: Clojure 's pipe : Ruby 2.7: The Pipeline Operator Emacs Lisp: F# pipeline: ReasonML pipeline: TypeScript pipeline: Python pipeline: Haskell pipeline: (|>) :: a -> (a -> b) -> b
(|>) x f = f x Bash pipeline: Rust pipeline: use std::ops::Shr;
struct Wrapped<T>(T);
impl<A, B, F> Shr<F> for Wrapped<A>
where
F: FnOnce(A) -> B,
{
type Output = Wrapped<B>;
fn shr(self, f: F) -> Wrapped<B> {
Wrapped(f(self.0))
}
}
fn main() {
let string = Wrapped(1) >> (|x| x + 1) >> (|x| 2 * x) >> (|x: i32| x.to_string());
println!("{}", string.0);
}
// prints `4` Julia pipeline: julia> Base.|>(xs::Tuple, f) = f(xs...)
|> (generic function with 7 methods)
julia> let
x = 1
y = 2
# just messing around...
(x, y) |> (x, y) -> (2x, 5y) |>
divrem |>
complex |>
x -> (x.re, x.im) |>
divrem |>
(x...) -> [x...] |>
sum |>
float
end
0.0 CommonLisp: C# static class Extn {
public static U Then<T,U>(this T o, Func<T, U> f) { return f(o); }
public static U Then<T, U>(this T o, Func<T, Func<U>> fe) { return fe(o)(); }
}
… which lets you write the more-readable:
var blah = "576 "
.Then<string,string>(x => x.Trim)
.Then(Convert.ToInt32); C++ pipeline: C++20 pipeline: auto dangerous_teams(std::string const& s) -> bool {
return s
| views::group_by(std::equal_to{})
| views::transform(ranges::distance)
| ranges::any_of([](std::size_t s){
return s >= 7;
});
} |
I am in favor of this 👍 |
I'm not in favor, but I'm also not super opposed. I'm mostly ¯_(ツ)_/¯. |
We discussed this briefly in today's sync call. We agreed that we want to continue discussing here in this issue ticket and in Zulip to try make sure that what we come up with is as useful as we can make it. @SeanTAllen mentions that he is wanting us to try to come up with something that will solve problems more broadly than this current proposal does. I mentioned that I'm generally in favor of things like this if they solve some problems and mostly stay out of the way when you don't need them. But of course if we can solve more problems with a different proposal, I'm likely in favor of that. Others mentioned that they can remember wanting something like this in Pony at various points in time. |
Discussed in today's sync call:
|
@SeanTAllen, if you have 4½ minutes to spare, Dave Thomas makes a compelling argument for the pipeline operator in his presentation "Think Different". |
Let's get more comment on this and see where we are next week. If anybody is interested in writing an RFC (@damon-kwok, @jkankiewicz?) please feel free to do that. If you have any questions about doing that please ask for help in this issue. |
a |> f
// equivalent to
f(a) b |2> f(a) // or b |1> f(a) if starting at 0
// equivalent to
f(a, b) b |b_arg> f(a)
// equivalent to
f(a, where b_arg = b) |
Pipe Operator
The pipe operator
|>
passes the result of an expression as the first parameter of another expression.The pipe operator
|>>
passes the result of an expression as the last parameter of another expression.Example
The text was updated successfully, but these errors were encountered: