3
votes

I'm a neophyte of Elixir and I'm learning and reading something about list/enum usage and function piping.

I learned how to combine Enum.map and Enum.each, e.g. manipulating the content of a list and printing the results list to console through

people = ["Qui", "Quo", "Qua"]
people
    |> Enum.map(&String.upcase/1)
    |> Enum.map(&Hello.hello/1)
    |> Enum.each(&IO.puts/1)

I'm wondering if it exists a library function that combines Enum.map and Enum.each together: my idea is to do something for list's each element AND return the untouched list, in order to proceed piping function calls. Sure, I can add side-effects to the function passed to Enum.map, but I don't like this approach very much and I would like to keep side effects explicitly separated from functional transformations.

I read Enum and List documentation, but I can't figure how do this: Enum.each returns :ok and I can't find something similar returning the initial list.

So I implemented it myself as follows:

defmodule MyEnum do 
    def tee list, action do
        Enum.map(list, fn item -> 
            action.(item)
            item
        end)
    end
end

(disclaimer: sure, I added side effects to map, but I isolated this dirtyness into a function whose name should clarify my intent) and rewrote the previous example as

people = ["Qui", "Quo", "Qua"]
people
    |> Enum.map(&String.upcase/1)
    |> Enum.map(&Hello.hello/1)
    |> MyEnum.tee(&IO.puts/1)
    |> Enum.map(&String.upcase/1)
    |> Enum.each(&IO.puts/1)

I works (and It was didactically very useful, for me, to wrote this code), but I'm wondering

  1. if there is something built-in in the standard library
  2. if my hand-made solution is a good and idiomatic solution in Elixir

Thanks in advance!

1

1 Answers

3
votes

Stream.each will do what you want but you will need to consume the stream to trigger the effects.

Executes the given function for each item.

Useful for adding side effects (like printing) to a stream.

people 
|> Enum.map(&String.upcase/1) 
|> Stream.each(&IO.inspect/1) 
|> Enum.to_list