最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

functional programming - Has anyone proposed a Pipe operator for javascript? - Stack Overflow

programmeradmin3浏览0评论

Many languages have an operator that allows you to pipe the results of one operation into a call to another (e.g. the | operator in bash, the |> operator in F#).

One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:

var fooOddSquares = [1, 2, 3, 4, 5]
    .filter(x => x % 2)
    .map(x => "foo" + x * x)
    .reduce(((acc, str, i) => acc[i + 1] = str; return acc), {});

// => {1: "foo1", 2: "foo9", 3: "foo25"}

compared to compositional code:

var something = func5(
    func4(
        func3(
            func2(
                func1(
                    somedata
                )
            )
        )
    )
);

which reads right-to-left, bottom-to-top. I realize this could be cleaned up via function composition, but that's not necessarily the point. Just to be absolutely clear with what I'm looking for:

var something = func1(somedata)
    |> func2
    |> func3
    |> func4
    //etc...

Doing a google search on the pipe operator in javascript mostly turns up info about the bitwise OR operation. With some digging however I was able to dig up this article describing a dirty-hacked version of operator overloading that could implement something of what I'm talking about. I also unearthed this gist that describes said operator and says that "it has been proposed for javascript".

Looking at ES 2016, I see proposals for an exponentiation operator and the bind operator. Both are useful, but not what I want. So per the headline in the gist, has anyone actually proposed this for javascript?

Many languages have an operator that allows you to pipe the results of one operation into a call to another (e.g. the | operator in bash, the |> operator in F#).

One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:

var fooOddSquares = [1, 2, 3, 4, 5]
    .filter(x => x % 2)
    .map(x => "foo" + x * x)
    .reduce(((acc, str, i) => acc[i + 1] = str; return acc), {});

// => {1: "foo1", 2: "foo9", 3: "foo25"}

compared to compositional code:

var something = func5(
    func4(
        func3(
            func2(
                func1(
                    somedata
                )
            )
        )
    )
);

which reads right-to-left, bottom-to-top. I realize this could be cleaned up via function composition, but that's not necessarily the point. Just to be absolutely clear with what I'm looking for:

var something = func1(somedata)
    |> func2
    |> func3
    |> func4
    //etc...

Doing a google search on the pipe operator in javascript mostly turns up info about the bitwise OR operation. With some digging however I was able to dig up this article describing a dirty-hacked version of operator overloading that could implement something of what I'm talking about. I also unearthed this gist that describes said operator and says that "it has been proposed for javascript".

Looking at ES 2016, I see proposals for an exponentiation operator and the bind operator. Both are useful, but not what I want. So per the headline in the gist, has anyone actually proposed this for javascript?

Share Improve this question asked Nov 5, 2015 at 16:54 Jared SmithJared Smith 21.9k5 gold badges49 silver badges92 bronze badges 7
  • Do you mean Promise.then()? – Kijewski Commented Nov 5, 2015 at 16:56
  • 1 JS is functional, but doesn't allow you to add custom operators. It's trivial to do with a custom function though, and has been done. – Bergi Commented Nov 5, 2015 at 16:57
  • 1 Yes...ish. You can certainly do that with Promises, but I mean an infix operator. – Jared Smith Commented Nov 5, 2015 at 16:58
  • Maybe you should just ask impinball about his gist? – Bergi Commented Nov 5, 2015 at 17:00
  • 1 Here the |> operator seems to be implemented using a sweet.js macro – Bergi Commented Nov 5, 2015 at 17:04
 |  Show 2 more comments

4 Answers 4

Reset to default 15

A pipeline operator has been proposed for ES7 (ES2016) in December 2015.

https://github.com/mindeavor/es-pipeline-operator

As mentioned already a pipeline operator has been proposed for ES7 (2016), however that doesn't help much if you want to use something like this right now with babel which exactly how I came across this question 9 months later.

The biggest hitch in supporting the es-pipeline-operator proposal through babel as far as I know is the current inability to use |> or <| as operators which create syntax errors and cannot be fixed without changes to babel and unfortunately does not look like the problem will be resolved any time soon.

I would personally like to see the pipe backward operator added to the proposal as well since both forward and backward are useful in different situations.

For example, I use the pipe backward operator when modifying functions or anywhere I would typically use "compose" over "pipe" which I prefer in certain situations for readability.

const something = curry <| function(state, pattern) {
  // something
}

const something = function(state, pattern) {
  // something
} |> curry

Because these pipe operators are incredibly useful in functional style javascript programming and for the benefit of anyone who came looking for a solution to use this right now like me, I have made a babel plugin that uses the bitwise operators << and >> which I rarely use to achieve both forward and backward piping for the time being and in the rare cases where the bitwise operators are required the use of the "no pipe"; directive will disable the plugin for a certain scope.

https://github.com/michaelmitchell/babel-plugin-pipe-composition

This github repo and my favorite issue within it ;) discuss just that.

The proposal has been moving around in a small neighborhood of ideas for some months, but centers around using -> and :: as sugar around Function.prototype.apply and Function.prototype.bind, very roughly.

The current draft is for :: to sit between a scope and function (instance::method) and act much like instance.method.bind(instance), locking the this scope of the function for any calls. Alongside that, -> may be defined to pass a scope and array of arguments (as apply), so instance->method(foo, bar) would desugar to instance.method.apply(instance, [foo, bar]). At least, that's one of the directions that is being discussed (disclosure: that's my take on it).

I usually just go like this:

var something = [somedata].map(func1).map(func2).map(func3).map(func4)[0];

It solves one of the main points in the question

One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:` by taking advantage of how this already exists for arrays.

because this feature already exists for arrays, and converting something into an array, and back again is easy enough.


the above uses the names in the question, but here is a concrete example:

console.log([9.3].map(Math.floor).map(Math.sqrt)[0]);
// or even this:
[9.3].map(Math.floor).map(Math.sqrt).forEach(x => console.log(x));

发布评论

评论列表(0)

  1. 暂无评论