SteveB
SteveB

Reputation: 981

Elixir: How to handle an "environment"

I've got a fairly big "pipeline" of functions processing a stream of inputs. Before the pipeline starts an "environment" map is created that will provide additional information for the functions in the pipeline. What I'm doing now, which seems to be what Elixir demands is to explicitly pass the environment into each function.

I'm a bit uneasy about the readability of the requirement that each function in the pipeline (and many of the functions they call) requires the environment as an argument. On the other hand I certainly understand that this may just be a part of "doing it functionally".

My question is: Am I missing something, perhaps an idiom, to handle this issue, or should I just get used to passing what seem like "extra" arguments as part of the functional programming world?

Thanks.

Upvotes: 4

Views: 274

Answers (1)

bitwalker
bitwalker

Reputation: 9261

I would suggest using Agents for this. The following is completely made up, but shows you the different operations, and resembles how you might want to approach it:

def process(data) do
  {:ok, agent} = Agent.start_link(fn -> %{data: data, count: 0} end)
  process(data, agent)
end

def process(agent) when is_pid(agent) and bar > 0 do
  transformed = do_stuff_with(data)
  Agent.get_and_update(agent, fn %{count: count} = state ->
    updated = %{state | :data => transformed, :count => count + 1}
    {updated, updated}
  end
  process(agent)
end

def process(agent) when is_pid(agent) and bar == 0 do
  Agent.cast(agent, fn %{count: count} = state ->
    %{state | :count => count + 1}
  end
  process(agent)
end

def process(agent) when is_pid(agent) do
  Agent.get(agent, fn state -> state.data end)
end

Instead of passing state, you pass the PID of the agent around, and get/update the Agent's state as needed.

Upvotes: 4

Related Questions