The whole get_in/2
and update_in/3
are Elixir version of lenses which is functional structure for handling and manipulating nested structure. In it core functionality these are 2 functions:
-
get
which extracts data from the structure
-
set
which put data within structure
So get_in/2
can be thought as a list of functions that will extract value from structure in form:
get_in(stuct, [f, g])
# is (roughly) the same as
g(f(struct))
# and
update_in(struct, [f, g], val)
g(f(struct, val), val)
In reality it is “slightly” more complicated as you cannot return “closured object” with multiple functions in Elixir. So instead it works like that:
f =
fn
:get, struct, next -> # extract value and call `next` on it
:update_in, struct, next -> # call next on data and then update `struct`
end
So in the end, example implementation of Access.key!
:
def key!(key) do
fn
:get, %{} = data, next ->
# call `next` on extracted data
next.(Map.fetch!(data, key))
:get_and_update, %{} = data, next ->
# get "current data" under key
value = Map.fetch!(data, key)
# call `next` on current value
case next.(value) do
# return value and update structure
{get, update} -> {get, Map.put(data, key, update)}
# remove value from structure
:pop -> {value, Map.delete(data, key)}
end
_op, data, _next ->
raise "Access.key!/1 expected a map/struct, got: #{inspect(data)}"
end
end