The thing is, this dedicated pipeline also requires adding some form of currying functions to the language. Why, in this case, do you call f
with one too few arguments? (It all depends on how UMCS goes, I guess, as that would also make “any” first argument the “self
” argument.)
The problem with pipelining based on the first argument is that it privileges the first argument of free functions when they’ve never been before. E.g. Haskell functions and Rust methods are designed such that the “privileged” position (first in Rust, last in Haskell) are the “complicated” type that you’d build before and chain on, but free functions in Rust have no such idiom, which a non-closure based pipelining proposal immediately retroactively adds to every function.
Compare also "UMCS match
" with closures instead:
z |> f(42) |> bar(v) |> |x| baz(9, x) |> spam;
z.match { x => f(x, 42) }.match { x => bar(x, v) }.match { x => baz(9, x) }.match { x => spam(x) };
z.pipe(|x| f(x, 42)).pipe(|x| bar(x, v)).pipe(|x| baz(9, x)).pipe(spam);
And my Pipe
trait doesn’t need anything new in the language, even! It may be longer, but it’s clearer as it doesn’t add currying semantics where there are none. And consider a syntax that uses _
for explicit currying:
z |> f(42) |> bar(v) |> |x| baz(9, x) |> spam;
z |> «f(_, 42)» |> «bar(_, v)» |> «baz(9, _)» |> spam;
z.pipe(«f(_, 42)»).pipe(«bar(_, v)»).pipe(«baz(9, _)»).pipe(spam);
z.pipe(|x| f(x, 42)).pipe(|x| bar(x, v)).pipe(|x| baz(9, x)).pipe(spam);
(«»
used to provide explicit scoping to the _
-created curry, as that’s the biggest issue to making it work)