Prashere
Prashere

Reputation: 167

Why does pattern matching Map with Tuple inside Stream/Enum module in Elixir Works?

If I have understood correctly, tuples in elixir are represented with {} while Maps are represented as a key:value pair with %{key: value}.

In the following code, the Stream.filter and Enum.map accepts entries as input, which is a Map and iterates over it.

But the lambda function inside them is doing a pattern matching on {_, entry} which is a tuple. How come this works?

defmodule TodoList do
   defstruct auto_id: 1, entries: %{}

   def new(), do: %TodoList{}

  def add_entry(todo_list, entry) do
    entry = Map.put(entry, :id, todo_list.auto_id)
    new_entries = Map.put(
      todo_list.entries,
      todo_list.auto_id,
      entry)

    %TodoList{todo_list |
      entries: new_entries,
      auto_id: todo_list.auto_id + 1
    }
  end

  def entries(todo_list, date) do
    todo_list.entries
    |> Stream.filter(fn {_, entry} -> entry.date == date end)
    |> Enum.map(fn {_, entry} -> entry end)
  end
end

Upvotes: 1

Views: 355

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Iterations in Elixir are possible by the implementation of Enumerable protocol. That means, anything, implementing Enumerable can be iterated using methods from Enum and String modules.

The implementation of this protocol for Map delegates to Enumerable.List.reduce/3, passing the map converted to a list with :maps.to_list/1.

The latter transforms the map to a list in the form [{k1, v1}, {k2, v2}, ...].

iex|1 ▶ :maps.to_list(%{k1: :v1, k2: :v2})
#⇒ [k1: :v1, k2: :v2] # essentially the list of tuples
iex|2 ▶ [k1: :v1, k2: :v2] == [{:k1, :v1}, {:k2, :v2}]
#⇒ true

These tuples are being emitted in Enum.map in your example.

Upvotes: 8

Related Questions