Why does Flow.reduce return a list of tuples

I’m currently looking at Flow and I can’t understand why every example that reduces the events into a map with a reduce stage return a list of tuples if we pipe the flow into a Enum.map(&(&1)), Enum.sort() or Enum.to_list().

If we look at the example given on the Flow.reduce/3 docs, this is exactly what happens:

    iex> flow = Flow.from_enumerable(["the quick brown fox"]) |> Flow.flat_map(fn word ->
    ...>    String.graphemes(word)
    ...> end)
    iex> flow = flow |> Flow.partition |> Flow.reduce(fn -> %{} end, fn grapheme, map ->
    ...>   Map.update(map, grapheme, 1, & &1 + 1)
    ...> end)
    iex> Enum.sort(flow)
    [{" ", 3}, {"b", 1}, {"c", 1}, {"e", 1}, {"f", 1},
     {"h", 1}, {"i", 1}, {"k", 1}, {"n", 1}, {"o", 2},
     {"q", 1}, {"r", 1}, {"t", 1}, {"u", 1}, {"w", 1},
     {"x", 1}]

My interpretation is that each reduce stage is definitely returning the map resulting from the Map.update/4 operation, but each individual map is being converted into a list on an intermediate step (since %{1 => 2, 3 => 4} |> Enum.map(& &1) == [{1, 2}, {3, 4}]). Why is this? Is there a way for me to get the “raw” reduce result from each stage?

Thanks in advance!

The reason probably is that under the hood, the different Flow calls call Enum.map or one of the other Enum-operations. These work using the Enumerable protocol, which will always convert the enumerable, no matter what it was, to a list as part of its inner workings.

For many functions that Enum provides this can be overridden by supplying a collectable as optional second (or third, i.e. for functions that support it always the last), into which the results will then be collected.

Asides from this, Enum.sort will always return a list, as many other containers (notably including maps) are not ordered.

5 Likes