Collectable protocol
A protocol to traverse data structures.
The Enum.into/2
function uses this protocol to insert an enumerable into a collection:
iex> Enum.into([a: 1, b: 2], %{}) %{a: 1, b: 2}
Why Collectable?
The Enumerable
protocol is useful to take values out of a collection. In order to support a wide range of values, the functions provided by the Enumerable
protocol do not keep shape. For example, passing a map to Enum.map/2
always returns a list.
This design is intentional. Enumerable
was designed to support infinite collections, resources and other structures with fixed shape. For example, it doesn’t make sense to insert values into a range, as it has a fixed shape where just the range limits are stored.
The Collectable
module was designed to fill the gap left by the Enumerable
protocol. into/1
can be seen as the opposite of Enumerable.reduce/3
. If Enumerable
is about taking values out, Collectable.into/1
is about collecting those values into a structure.
Examples
To show how to manually use the Collectable
protocol, let’s play with its implementation for MapSet
.
iex> {initial_acc, collector_fun} = Collectable.into(MapSet.new()) iex> updated_acc = Enum.reduce([1, 2, 3], initial_acc, fn elem, acc -> ...> collector_fun.(acc, {:cont, elem}) ...> end) iex> collector_fun.(updated_acc, :done) #MapSet<[1, 2, 3]>
To show how the protocol can be implemented, we can take again a look at the implementation for MapSet
. In this implementation “collecting” elements simply means inserting them in the set through MapSet.put/2
.
defimpl Collectable do def into(original) do collector_fun = fn set, {:cont, elem} -> MapSet.put(set, elem) set, :done -> set _set, :halt -> :ok end {original, collector_fun} end end
Summary
Types
Functions
- into(collectable)
-
Returns an initial accumulator and a “collector” function
Types
command()
command() :: {:cont, term()} | :done | :halt
t()
t() :: term()
Functions
into(collectable)
into(t()) :: {term(), (term(), command() -> t() | term())}
Returns an initial accumulator and a “collector” function.
The returned function receives a term and a command and injects the term into the collectable on every {:cont, term}
command.
:done
is passed as a command when no further values will be injected. This is useful when there’s a need to close resources or normalizing values. A collectable must be returned when the command is :done
.
If injection is suddenly interrupted, :halt
is passed and the function can return any value as it won’t be used.
For examples on how to use the Collectable
protocol and into/1
see the module documentation.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.6.6/Collectable.html