This is one of my favorite patterns, the _guarded suffix. You do all your guard checks in your public function, and you delegate to a private one and call it recursively if needed, without checking for a guard again and increasing performance.
This is the current implementation for Keyword.update/4
@spec update(t, key, default :: value, (existing_value :: value -> new_value :: value)) :: t
def update(keywords, key, default, fun)
when is_list(keywords) and is_atom(key) and is_function(fun, 1) do
update_guarded(keywords, key, default, fun)
end
defp update_guarded([{key, value} | keywords], key, _default, fun) do
[{key, fun.(value)} | delete(keywords, key)]
end
defp update_guarded([{_, _} = pair | keywords], key, default, fun) do
[pair | update_guarded(keywords, key, default, fun)]
end
defp update_guarded([], key, default, _fun) do
[{key, default}]
end






















