Assume concat
is some function sticking two strings together, and uppercase
is... well:
Haskell (argument application):
> let a |> f = f a
> "def"
|> (\x -> concat "abc" x)
|> uppercase -- (\x -> uppercase x) if you want to be explicit.
|> (\x -> concat "Alphabet: " x)
"Alphabet: ABCDEF"
-- (For completeness, the shortcut version: auto-currying means calling a
-- two-arg function with one arg means you get back a function that expects one arg.)
> "def"
|> concat("abc")
|> uppercase
|> concat("Alphabet: ")
"Alphabet: ABCDEF"
JS/ES7 with https://github.com/mindeavor/es-pipeline-operator (argument application)
> "def"
|> x => concat("abc", x)
|> uppercase // (x => uppercase x) if you want to be explicit.
|> x => concat("Alphabet: ", x)
Alphabet: ABCDEF
Elixir (syntax macro):
> "def" |> Foo.concat("abc") |> Foo.uppercase |> Foo.concat("Alphabet: ")
"DEFABCAlphabet: "
Haskell and the proposed ES7 change, for each of the "steps", calls the function on the right with the value from the left. (Haskell just has an "auto-currying" shortcut [the second example], that makes this look nicer.)
Elixir does a syntax shuffle with the |>
macro (not function); it takes what's being passed along and puts into the first slot, and moves the other arguments along. It's not possible to do this "in-universe" without breaking out reflection to access and monkey with arguments
.
Further breaking down the JavaScript example from the proposal:
var result = "hello"
|> doubleSay
|> capitalize;
You can think of x |> myFunction
as some function called |>
with two arguments, eg. pipeOp(x, myFunction)
.
So then "hello" |> doubleSay |> capitalize
could be thought of as: pipeOp(pipeOp("hello", doubleSay), capitalize)
.
If we assume that pipeOp = function(val, func) { return func(val) };
... then you get: capitalize(doubleSay(x))
... And therefore: result === "HELLOHELLO"
(Whether the actual implementation matches the above is irrelevant; that's how it works when you use it.)
This is in contrast to Elixir where it's doing something with the tokens in the programming language itself, and inserting an argument in the first position, as opposed to the above where it's "just functions".
FWIW, you can do the same thing in Elixir albeit with more explicit syntax. Giving it the same semantics as the Haskell/JS versions.