functional-programmingelixir

What are the values in the acc and x in every enumeration in the Elixir code below found in the Enumerable Protocol official docs?


I am trying to dissect and understand how the acc/0 and reducer/0 work within the Enumerable Protocol.

def map(enumerable, fun) do
  reducer = fn x, acc -> {:cont, [fun.(x) | acc]} end
  Enumerable.reduce(enumerable, {:cont, []}, reducer) |> elem(1) |> :lists.reverse()
end

Could someone explain this starting from the values of x, acc in each enumeration



Solution

  • This is almost but not quite like the higher-level Enum.reduce/3, and similar "reduce" or "fold" operations in other functional languages. Enumerable is a lower-level Elixir protocol (interface) that types can implement to say that they are "a container" and can be used with the Enum function; reduce is the core building block.

    The reducer parameter will get called once for each element in the list, with the previous (or initial) value of the accumulator as that parameter. The Enumerable:acc/0 type for the accumulator parameter includes not just the value but also a control atom that tells the Enumerable implementation what to do, in particular with an option to stop early. :cont here means "continue", and in this example you will always iterate through the entire list.

    Let's say you call

    map([1, 2, 3], &(&1 * 2))
    

    Then the sequence of inner calls will be

    reducer.(1, [])      # {:cont, [2]}
    reducer.(2, [2])     # {:cont, [4, 2]}
    reducer.(3, [4, 2])  # {:cont, [6, 4, 2]}
    

    and the remaining logic splits off the :cont marker and reverses the list so it's in the correct order.