F# Pipeline Operator in JavaScript with Babel
codereform.com
codereform.com
https://stackoverflow.com/questions/3326826/language-history...
Python and Ruby: _
Shell: $?
HyperTalk: it (my first exposure to the concept, even though it was more of a convention)
Some Lisps: *, **, ***, ...
If we had that, then we could write: func1();
func2(_);
func3(_);
...
Which reminds me of PostScript, which lets you examine and manipulate the program's stack directly (the top of the stack is the previous result):http://www.ugrad.math.ubc.ca/Flat/intro.html
http://www.ugrad.math.ubc.ca/Flat/stack.html
If I were implementing it, I would make the previous result and stack contents read-only so that it's conceptually the same as the pipeline operator except that it allows inspecting the intermediate value.
Or if you return pointers.
f(g(h(x)))
Becomes
f g h x
Which I find very natural and better than
x h g f
Like in a stack language.
Haskell has $ operator (simple application operator but with low precedence—think open bracket that closes implicitly at the end of expression). While it makes your example a bit more verbose:
> f $ g $ h x
it also allows one to pass multiple arguments in an intermediate function call, e.g.
> f $ g x $ h y
is the same in Haskell as
> f (g x (h y))
which in most languages would be
> f(g(x, h(y))
(f . g . h) xRuby doesn't _ that way (IRB, the bundled Ruby REPL, does)—Ruby actually does have special handling for _ as a variable, but that's to suppress duplicate definitions n warnings to allow it to be used as a don't-care argument.
I think Python is similar, where it is special-cased in the REPL, not a general language feature.
Also, don't be turned off by the sea of comments. Pick one, they are all great. but yes ML language enthusiasts can be a bit overenthusiastic, but I don't fault them for that. They are all anxious to spread the gospel of ML. The Reason community on discord is excellent, one of the best I have had the pleasure to be a part of.
I didn't go with straight OCaml with js_of_ocaml because I wanted a better representation of what I was doing in JS land. There is an excellent write-up about it here: https://www.javierchavarri.com/js_of_ocaml-and-bucklescript/
...or Blazor
https://news.ycombinator.com/item?id=17842400 ctrl-f "vmchale"
import Data.Function as F
infixl 1 F.applyFlipped as |>That is really cool. I wish Haskell & Purescript weren't so difficult to grok, trying them has been on my todo-list for ages but they're so different than any other language.
F.applyFlipped blah rhubarb
blah `F.applyFlipped` rhubarb
blah |> rhubarb
(|>) blah rhubarb
The number (1) is the precedence, so if you have multiple operators in a statement it knows how to group them.[1] https://caml.inria.fr/pub/docs/manual-ocaml/libref/Stdlib.ht...
Was added to OCaml 2013-09-12[0]
F# was based on 3.xx, or maybe, even, 2.xx OCaml.
https://docs.microsoft.com/en-us/archive/blogs/dsyme/archeol...
After all, it should rightfully be attributed to the Isabelle/ML programming lanaguage[0][1]
[0]https://isabelle.in.tum.de/ [1]https://docs.microsoft.com/en-us/archive/blogs/dsyme/archeol...
I'm actually glad that this kind of composition is growing in popularity. Back when I did F# for a living, I loved that by using the pipe operator, you could get something more or less akin to a fluent interface, without any direct coupling between the two composed functions, and without any gross intermediate variables. I have nothing against "regular" point-free composition or anything like that, but I do think that these pipe operators are easier to digest for a lot of purposes.
I think people are stuck in the "C MACROS ARE BAD" thinking. It is a really powerful feature. CLOS, the world's most flexible oo system, was conceived as a bunch of macros. Racket's pattern matching is really just a macro (that could almost be called a compiler). Useful things that can be syntactically integrated into a language as an afterthought, yet still look and feel first class.
In fairness to a lot of people, I think that most of the folks in the "MACROS ARE BAD!!!" crowd are under the impression that C macros are the only way people do them, and assume that even Lisp macros are just are also just glorified text-expansion. I would be against macros too if that were the case.
> I would be against macros too if that were the case.
I wouldn't; even text expansion macros are useful, and can be done better than what is in C.
Using C preprocessing as an example criticize only textual/token macro expansion is still a strawman.
It makes a great alternative to fiddling with prototypes or wrapper objects when you want to extend something.
For example, this is flat-map implemented as a free function:
const flatMap = f => {
if (!f) {
throw new TypeError('f must be a function');
}
return xs => ({
[Symbol.iterator]: function * () {
for (const x of xs) {
yield * f(x);
}
}
});
};
// Usage
const xs = [ 1, 2, 3 ] |> flatMap(x => [ x, -x ]);pipe(2, add(2), square, n => n + 7) // -> 23
Nothing fancy but comes in handy at times.
What I really miss is something like the |> from Elixir. Maybe it's the same as F#, I don't know, but it automatically performs partial application, so that:
Enum.filter([1, 2, 3, 4], fn n -> n % 2 == 0 end)
also works like:
[1, 2, 3, 4] |> Enum.filter(fn n -> n % 2 == 0 end)
ppipe([1, 2, 3, 4]).pipe(Enum.filter, _, x => x % 2 === 0)
Not that filter fn in js is in the prototype of arrays so you'd need to extract it. There's a shortcut when using my library though: ppipe([1,2,3]).filter(x => x > 2)
I made the practical decision to provide prototype functions from the piped value while chaining.Now, I understand how it might be desirable to NOT having to use Babel to run code, especially on Node. On the other hand, some amount of transpilation has become inevitable for js in the browser and I don't see this need going away soon, as JS evolves much quicker than browser adoption.
From what I hear from tc39 people, method extraction is one of the biggest must-haves holding this thing up. They want a nice way to bind contexts to an entry in the pipe. Ironically the difficulty of figuring this out for JS is keeping pipes out of TS, but it wouldn't be that hard a problem in TS which has ways to treat `this` as special already.
That, and the many competing proposals we already have. I'm fine doing an incremental rollout that doesn't need the placeholder `?` right now.
Getting something through the TC39 is a pretty lengthy process, you can read about it here https://tc39.es/process-document/.
If you are part of one of these companies and interested in this proposal, it'd be super cool to see who you need to talk to to influence this decision.
Hitachi
IBM
Intel
Konica Minolta
Microsoft
PayPal
Stripe, Inc.
Ironically, JavaScript has the extensibility mechanisms and object-oriented features inspired by Smalltalk that could allow for pretty much the same thing. However, most of the community doesn't seem to even realize that this is a possibility.
The result is that if I whine, I whine about the choice of language, not about how a particular part of a language sucks. Extensibility like that should be built in, and then probably mostly discouraged. If you really need to scratch an itch, you will be able to do so without resorting to what usually ends up as ugly, non-composable hacks.
Also, many entities listed on Ecma's membership page are not there for TC39, and talking to people working for them will not get you anywhere.
[1] https://github.com/tc39/proposal-pipeline-operator [2] https://github.com/tc39/notes/blob/master/meetings/2018-03/m...
Javascript, Java, Python, C, C++, C#, PHP, Swift†, Ruby†, SQL†, Go†, VBA†, TypeScript†, Kotlin† and that's about it.
The languages with a dagger (†) are either niche languages or tied to a very specific (albeit very popular) platform.
Which one of them has the pipeline operator, especially in widespread use in libraries in its ecosystem? Personally, I don't know of any.
I'm not saying that what this blog post presents has achieved mass adoption, I'm just arguing that the pipeline operator for standard programming languages hasn't reached mass adoption, anywhere. I don't count Unix pipes as being the same thing as the pipeline operator, in this context ;-)
This is currently #5 on HN: https://www.infoq.com/articles/java-14-feature-spotlight
It's a pretty long read and could have done with some precedent.
My fear is that JS is trying to be all things to all developers- it feels like we just added the `class` keyword for the OO inclined and now we're moving towards functional programming? Do we really want to move further away from the idea of idiomatic JS?
But who knows, maybe it will open the door to massive productivity and enjoyability gains with the language...
The pipe operator is a super-basic transformation of the AST. In exchange, you get much easier to read "nested" functions. `foo(bar(baz(x))) --> x |> baz |> bar |> foo` is very easy to teach and very easy to understand.
It's hardly a fair comparison.
It’s just a meme, used correctly, what’s the problem? This isn’t the White House’s blog.
To me, that image was superfluous and likely to perpetuate the "boys club" appearance of tech.
Sure, the author can put whatever they want on their site. But why go to the trouble of writing something and then tossing in a Piss Off message to some of the readership?
f1(?) |> ( f2(?), I ) |> f3(?) == f1(?) |> f2(?) |> f3(?) , f1(?) |> f3(?)
it just feels natural that way
https://bitbucket.org/bjoli/guile-threading-macros/src
I wrote it when I was a beginner at syntax-rules macros, but it gets the job done. It doesnt do destructing though!
const pipe = (...args) => args.reduce(async (acc, fn) => fn(await acc));
No actual third party libraries requiredYou could always stick a breakpoint at the start of bar, quax or hotdog and see what was passed in?
(Many debuggers already support that last bit of inserting breakpoints inside of lines instead of "at" lines, it's just not as obvious as the usual "click the spot to the far left gutter of the line you want". Sometimes it is something like a Right-Click on the specific part of the line and look for a command such as "Insert Breakpoint Here". It's something to learn if your chosen debugger supports today.)
The obvious tangent here, of course, is that many times when you might want to heavily use something like a pipeline operator you are likely working with something more abstract between function calls like an Iterator/Generator pattern (or an Observable pattern), and debugging those require different habits/tools as the "intermediate results" aren't directly interesting (an Iterator is "just" an object with a next() function, it's not an array of intermediately processed data). Learning to debug those patterns is its own skillset (whether or not you are using a pipeline function or a pipeline operator or old-fashioned function call syntax), but one common example is a function you'd add inside the pipeline often called something like a "tap". In that case you might "tap" in to the middle of a pipeline to log intermediate results. Something like:
x |> f |> tap(y => console.log(y)) |> g f . g = \x -> f (g x)
f |> g = \x -> g (f x)`(&) :: a -> (a -> b) -> b`
https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-...
flip ($)