Many significant apologies for reopening this very-very-well-treaded topic, 
but I do want to advocate this *one* more time.

The pipe operator is used to illustrate the flow of data transformation, 
but while functional programming is very expressive, there are times when a 
signature requires the data in question to be used as a different argument. 
In those cases, you must either break the pipe chain (and thus the flow of 
data transformation) to assign the transformed data to a variable, or send 
the data through an anonymous function to continue the program flow.

Take a process where data should be transformed before being saved to a 
database:

# intermediary value
def encrypt_password(user, password) do
  encrypted = password
    |> Salt.add
    |> BCrypt.hash
  put_in(user[:hashed_password], encrypted)
    |> EctoOrSomething.UpdateIGuess.ImStillNewHere
end

# anonymous function wrap

def encrypt_password(user, password) do
  password
    |> Salt.add
    |> BCrypt.hash
    |> (fn(encrypted) -> put_in(user[:hashed_password], encrypted) end).()
    # or |> (&(put_in(user[:hashed_password], &1)).()
    # but considerably messy either way
    |> ...
end

The main issue in conceptualizing a more elegant workflow to represent 
these transformations is that any construct implemented will make an 
affordance in one direction or the other. A pipe-to-argument operator would 
offer strong reusability, but proposals in this group suggested a token 
that poorly expresses its usage (I'm thinking of a thread where ~| had been 
proposed as an anonymous variable binding with |>) . The other proposals 
are for inflexible cases that would necessitate more extensions for further 
implementations, and/or borrow symbols from other languages that are 
ambiguous in their usage (such as proposals for <|, |<, and |>> as tokens 
for pipe-to-last).

I think Elixir is in a unique position to solve this problem, though. If I 
could draw a correlation, the pin macro, Kernel.^/1 is used to bind a 
variable in at a location for pattern-matching...

good_status = "200"
{^good_status, response} = fetch("www.example.com")
# expands to {"200", response} = fetch("www.example.com")

I believe there's syntactic justification for a new pipe macro, Kernel.|^/2, 
that would interact with a Kernel.^/0 macro, to combine the concepts of the 
pipe and the pin. Assuming the current pipe operator symbolically 
translates | to "pipe to" and > to "the left", |^ would represent "pipe to 
the pin". The pin would appear at least once in the expression on the right 
in order to represent where the expression on the left will appear, expanded, 
like such:

def encrypt_password(user, password) do
  password
    |> Salt.add
    |> BCrypt.hash
    |^ put_in(user[:hashed_password], ^)
    |> ...
# expands to ...(put_in(user[:hashed_password], 
BCrypt.hash(Salt.add(password)))
end

Benefits to this approach:

   - The current pipe operator behavior remains pristine
   - ^/0 continues to act as a reference to expanding a variable
   - No introduction of new symbolic concepts
   - Syntax is flexible enough to expand to any (or multiple) argument 
   position

# more contrived examples!!
> map = %{little_bunny: %{}}
> :foo
    |^ put_in(map[:little_bunny][^], ^)
%{little_bunny: %{foo: :foo}}

> "Ton" |^ (^<>"y! " <> ^<>"i! " <> ^<>"é!")
"Tony! Toni! Toné!"

Again, I know there've been many discussions about the drawbacks to 
implementing a new pipe mechanism, and the Elixir community may have 
already come to a consensus around how to handle transformations like this, 
but I think the longevity of this topic points to a desire for some kind of 
better solution.

If everyone is tired of talking about this, I'll happily let it end here, 
but I thought one more perspective couldn't hurt.

Thanks for reading! ^_^

On Wednesday, July 9, 2014 at 5:10:19 AM UTC-7, José Valim wrote:
>
> at the risk of being painfully obvious, this works:
>>
>> :crypto.rand_bytes(8)
>> |> Base.encode16
>> |> (&("--------FormDataBoundary" <> &1)).()
>>
>
> Yup, this form works and is usually the solution proposed for such cases.
>
> I concur that allowing such forms would be a special case for pipe and 
> possibly confusing in the long term. However, given that many were 
> expecting it to work, I decided to gather everyone's feedback. And based on 
> this thread, it doesn't seem we should change the pipe operator.
>
>
> *José Valim*
> www.plataformatec.com.br
> Skype: jv.ptec
> Founder and Lead Developer
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/5e14b193-4102-4ca9-991d-273b572727c2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to