Skip to content
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

Backwards pipe operator? #3

Closed
acdlite opened this issue Dec 6, 2015 · 19 comments
Closed

Backwards pipe operator? #3

acdlite opened this issue Dec 6, 2015 · 19 comments

Comments

@acdlite
Copy link

acdlite commented Dec 6, 2015

How about a backwards pipe operator as well?

const squareThenDouble = x => double(square(x))

// or use forward pipe
const squareThenDouble = x => x  |> square |> double

// or use backward pipe
const squareThenDouble = x => double <| square <| x
@bergus
Copy link

bergus commented Dec 7, 2015

x => double <| square <| x

really doesn't read much easier than

x => double(square(x))

Not enough benefit to warrant another new operator.

@acdlite
Copy link
Author

acdlite commented Dec 7, 2015

I use and enjoy the Elm version.

@acdlite
Copy link
Author

acdlite commented Dec 7, 2015

Also, semi-related: have you considered a composition operator as well?

const squareThenDouble = square >> double
const squareThenDouble = double << square

@acdlite
Copy link
Author

acdlite commented Dec 7, 2015

Although shoot, I guess those are already taken in JavaScript, haha :D

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

@roman01la
Copy link

@acdlite What about Haskell style for composition?

const squareThenDouble = double . square

@bergus
Copy link

bergus commented Dec 7, 2015

@roman01la That does't work as it obviously collides with the property access operator.

You could use Haskell Category syntax though

const squareThenDouble = double <<< square

@roman01la
Copy link

@bergus You are right.

My main concern for . was that it's just one character. There's also $ in Haskell.

const squareThenDouble = double $ square

@RangerMauve
Copy link

@roman01la $ would probably be worse than . since $ is often used as a name for variables.

@gusaiani
Copy link

gusaiani commented Dec 8, 2015

@bergus @roman01la I agree that the . is better than |>.
I also understand the potential conflict with property operator.

Having used the pipeline operator in Elixir quite a bit, and as it has no backward pipe, the symbol is just not great.

I wish I could suggest a great alternative, but even ... seems better.
Yeah yeah, there are the spreads and stuff.
Anyway, here’s to continue thinking about how to write the pipeline.
The main idea itself is awesome.

@texastoland
Copy link

Ultimately the utility of forward pipe is declarative data flow. Because JS isn't curried, its functions are rarely composable, negating compositional operators. Backpipe is particularly tricky, because F# (<|) and Haskell ($) apply opposing associativities. A tightly focused spec will be easier to champion.

@JakeCoxon
Copy link

I like it, it would add the ability to 'decorate' functions which is not covered by the decorator spec

transformSomeMore() <|
transformTheFunction() <|
function myFunction() {
}

@micahnz
Copy link

micahnz commented Aug 27, 2016

I am using the bitwise operators << and >> to achieve both forward and backward piping for now.

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

@TehShrike TehShrike added duplicate Duplicate of another bug and removed duplicate Duplicate of another bug labels Sep 22, 2016
@babakness
Copy link

babakness commented Jul 21, 2017

@bergus The comparison provided should be

const foo = double <| square 

versus

const foo = x => double(square(x))

To illustrate this, suppose we have

const add = a => b => b + a
const mul = a => b => b * a
const div = a => b => b / a

instead of writing this

const f2c = x => div(9)(mul(5)(add(-32)(x)))

We could just write

const f2c = div(9) <| mul(5) <| add(-32)

In chaining together data processing pipe is more natural, include the example I gave here.

const f2c = add(-32) |> mul(5) |> div(9)

Whereas when dealing with embedded components (common on the web, i.e. HTML), compose is more natural than pipe, i.e.

const updateSiteCart = template <| page <| cart
<template>
  <page>
    <cart />
  </page>
</template>

@madnight
Copy link

madnight commented Jul 21, 2017

i think we should keep the es-pipeline-operator proposal as minimal as possible, just provide a small concept that everyone can agree on, so that we have the biggest change of passing all the way down to stage-4, otherwise there is way to much potential for discussions

@joshburgess
Copy link

joshburgess commented Oct 2, 2017

It makes sense to include both directions. Many people who are into functional programming prefer right-to-left operators, like $ / <| (apply aka "pipe") or . / << / <<< (compose) in Haskell/Elm/F#/PureScript, etc., because you're already thinking in a mathematical way, and right-to-left is more consistent with that mindset.

However, there will inevitably be people who prefer the left-to-right/sequential style. So, there's no real reason to exclude either option, in my opinion. It would take almost no effort to include both |> and <|.

I think it's too restrictive to force only left-to-right style with only |>. Why not allow either direction? If you look at Elm, PureScript, F#, etc., it's left up to the user to choose which they prefer. Some people even use both together.

@TiddoLangerak
Copy link

@babakness I might be mistaken, but I think you're comparison is off: const foo = double <| square would be function composition, not pipelining. There's a different proposal for that. With pipelining you'd get what @bergus said:

const foo = x => double <| square <| x

Regardless of its usefulness, introducing a <| operator complicates this proposal, and it also has a much bigger abuse surface when you mix them. E.g.:

const foo = x => foo <| x |> bar
// vs
const foo = x => foo(x |> bar);
// or (depending on associativity of `<|` and `|>`)
const foo = x => foo(x) |> bar

I don't deny the usefulness of such an operator, but adding the <| operator right away will complicated and delay the entire proposal. As @madnight said, keeping |> as minimal as possible will help us advancing the proposal through the stages more quickly. When |> has landed a separate proposal for <| can easily be started.

@joshburgess
Copy link

joshburgess commented Oct 3, 2017

@TiddoLangerak I don't think it really complicates much. It's a directional binary operator. It's as simple as flipping the order of arguments of the underlying function. These are literally called apply and applyFlipped in other languages, because that's all they do.

Precedence would determine which happens first where both directions are used simultaneously... and precedence needs to be defined anyway.

@babakness
Copy link

@TiddoLangerak Interesting, thanks for clarifying.

@littledan
Copy link
Member

The backwards pipe operator may be pursued in a follow-on proposal. The scope of this proposal will be limited to |>.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests