Is it possible to choose where the pipe output is inserted into Elixir function args?
Asked Answered
B

3

9

Consider a (smelly, non-idiomatic) function like the below:

def update_2d(array, inds, val) do
    [first_coord, second_coord] = inds

    new_arr = List.update_at(array, second_coord, fn(y) ->
      List.update_at(Enum.at(array, second_coord),
        first_coord, fn(x) -> val end) end)
end

This function will take in a list of lists, a list of two indices, and a value to insert within the list of lists at the location specified by the indices.

As a first step to making this more Elixir-ey, I start laying pipe:

array 
  |> Enum.at(second_coord) 
  |> List.update_at(first_coord, fn(x) -> val end)

That gets me most of the way there, but how do I pipe that output into the anonymous function of the last List.update_at call? I can nest it within the original call, but that seems like giving up:

List.update_at(array, second_coord, fn(y) -> 
  array 
  |> Enum.at(second_coord) 
  |> List.update_at(first_coord, fn(x) -> val end) 
end) 
Busby answered 23/8, 2015 at 10:11 Comment(0)
M
10

You can simply bind to a variable to capture your first result and then replace it in the second List.update_at/3 call

def update_2d(array, inds = [first_coord, second_coord], val) do
  updated =
    array
    |> Enum.at(second_coord) 
    |> List.update_at(first_coord, fn(x) -> val end)

    List.update_at(array, second_coord, fn(x) -> updated end)
end

You can also use the capture operator to do this:

  def update_2d(array, inds = [first_coord, second_coord], val), do:    
    array
    |> Enum.at(second_coord) 
    |> List.update_at(first_coord, fn(x) -> val end)
    |> (&(List.update_at(array, second_coord, fn(y) -> &1 end))).()

I find using a variable much more readable, but the option is there.

Marquis answered 23/8, 2015 at 10:24 Comment(5)
Hahaha, that's true. I am trying to be so clever with the above.Busby
@TrevorAlexander I have also provided a way to do it without a temporary variable.Marquis
Ah! I was trying something like that but I was not capturing the whole call.Busby
Alternatively, you can just create a private function that receives the arguments in the proper order and then performs the call. :)Bowlder
What is worth noting about the capture method is that it frees you from coming up with a name (for a function or a temp variable). But personally I usually tend to use the "private function that receives the arguments" - that José mentioned.Dense
L
0

As of Elixir 1.12, there is the then\2. See the docs

|> then(fn x -> x * 2 end)
    
|> then(fn x -> Enum.drop(["a", "b", "c"], x) end)
["b", "c"]
Lamothe answered 18/5, 2023 at 7:1 Comment(0)
T
-2

How about:

{:foo, :bar} |> elem(1) |> Enum.Map(fn x -> x end)

Seems easier.

Theretofore answered 8/9, 2018 at 19:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.