My favourite approach to this so far, that I would like other libraries to copy, is Elixir’s Access protocol, which gives you e.g.:<p><pre><code> foo = %{key: [[1, 2], [3, 4], [5, 6]]}
path = [:key, Access.all, Access.at(0)]
get_in foo, path
# => [1, 3, 5]
update_in foo, path, &(&1 * 10)
# => %{key: [[10, 2], [30, 4], [50, 6]]}
foo
|> put_in([:key, Access.all], “foo”)
|> put_in([:new_key], “bar”)
# => %{key: [“foo”, “foo”, “foo”], new_key: “bar”}
</code></pre>
That third form is essentially the equivalent of building up a complex object through a series of mutations—but entirely functional.