Skip to content

Instantly share code, notes, and snippets.

@elainenaomi
Last active June 5, 2019 17:12
Show Gist options
  • Save elainenaomi/6ac112f40bf9bef20e8854e6f89a584c to your computer and use it in GitHub Desktop.
Save elainenaomi/6ac112f40bf9bef20e8854e6f89a584c to your computer and use it in GitHub Desktop.

Hello, world everyone

Context

I started to learn Elixir recently and I have a lot of simple questions 😅 I’m reading the Elixir in Action and I finished the first three chapters 🎉 I really enjoyed how Saša explained the basic concepts, for instance, introducing lists and explaining why we should push an element to the top of the list (with illustrations). He also described the big O notation for several basic operations and other aspects related to the compiler and Erlang VM memory allocation.

However, the part of Streams was very compact (compared to the part about lists). I know that it is a lazy enumerable and I understood (I hope) how to use it. But I missed some details about how Elixir compiler handles it.

He said that There are no special tricks in the Elixir compiler, describing that the secret is the anonymous functions and when the computation needs to be materialized, the consumer code can call the lambda.. And this last phrase really made to think about it all day long: Even though you stack multiple transformations, everything is performed in a single pass when you call Enum.each.

Problem

How does Elixir convert a stream pipeline to just one iteration? Does it simply get the functions that should be applied and serializes it? Assuming it, do these two pipelines are equivalent? 👀

stream = 1..3 
|> Stream.map(&IO.inspect(&1)) 
|> Stream.map(&(&1 * 2)) 
|> Stream.map(&IO.inspect(&1))
Enum.to_list(stream)
Enum.each(1..3, fn x -> 
 IO.inspect(x)
 |> Kernel.*(2)
 |> IO.inspect
end)

Bonus question

Considering this new version of previous code:

Enum.each(1..3, fn x -> 
 IO.inspect(x)
 |> Kernel.* 2
 |> IO.inspect
end)

Why does the example above not return an error or behave like the first one? Isn’t the parentheses optional in the |> Kernel.*? :thinking_face: If I had to take a guess, I'd say it happens because |> Kernel.* can be lazy evaluated (for some reason that I don’t know) and only the number 2 is provided to next step (|> IO.inspect). Or I maybe I found a bug or I should read these chapters again 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment