def update_in(*key_path, &block)
      if key_path.empty?
        raise ArgumentError, "must have at least one key in path"
      end
      key = key_path[0]
      if key_path.size == 1
        new_value = block.call(fetch(key, nil))
      else
        value = fetch(key, EmptyMap)
        new_value = value.update_in(*key_path[1..-1], &block)
      end
      return put(key, new_value)
    end
def update_in(*key_path, &block)
      if key_path.empty?
        raise ArgumentError, "must have at least one key in path"
      end
      key = key_path[0]
      if key_path.size == 1
        new_value = block.call(fetch(key, nil))
      else
        value = fetch(key, EmptyMap)
        new_value = value.update_in(*key_path[1..-1], &block)
      end
      return put(key, new_value)
    end
Return a new container with a deeply nested value modified to the result
 of the given code block.  When traversing the nested containers
 non-existing keys are created with empty `Hash` values.

 The code block receives the existing value of the deeply nested key/index
 (or `nil` if it doesn't exist). This is useful for "transforming" the
 value associated with a certain key/index.

 Naturally, the original container and sub-containers are left unmodified;
 new data structure copies are created along the path as needed.

 @example
   t = Erlang::Tuple[123, 456, 789, Erlang::Map["a" => Erlang::Tuple[5, 6, 7]]]
   t.update_in(3, "a", 1) { |value| value + 9 }
   # => Erlang::Tuple[123, 456, 789, Erlang::Map["a'" => Erlang::Tuple[5, 15, 7]]]
   map = Erlang::Map["a" => Erlang::Map["b" => Erlang::Map["c" => 42]]]
   map.update_in("a", "b", "c") { |value| value + 5 }
   # => Erlang::Map["a" => Erlang::Map["b" => Erlang::Map["c" => 47]]]

 @param key_path [Object(s)] List of keys/indexes which form the path to the key to be modified
 @yield [value] The previously stored value
 @yieldreturn [Object] The new value to store
 @return [Associable]